R cuenta con varios paquetes de funciones que permiten trabajar con bases SQL con facilidad. A continuación vamos a ver algunas herramientas y ejemplos de como trabajar las bases de datos de la BdeC con R.
Paquetes
Hay dos paquetes útiles para trabajar bases SQL DBI y RODBC. Asimismo, dplyr cuenta con funciones que permiten exportar las consultas a formato SQL.
library(RODBC)
library(tidyverse)
library(dbplyr)
Conexión a la base y consultas
Me conecto a la base con la funcion odbcDriverConnect.
ch <- odbcDriverConnect(
connection = "Driver=SQL Server; Server=BC-RETA;
Database=Estimaciones_copia;
UID=estimaciones_consulta;
Pwd=Esti.bc.201923"
)
Consulta SQL
sqlQuery permite utilizar el codigo de sql en R. La consulta se inserta como string.
En esta consulta seleccionamos se combinan 5 tablas y se selecciona para el cultivo trigo, en la campaña 18/19, en el nivel tecnologico alto, en la zona Retaa 5 las dosis de fertilizacion promedio.
consulta_Ruben <- sqlQuery(channel = ch, query = "--/////////////////////////////////////////////
--@id_consulta
--6 Fertilización
--7 Herbicidas
--8 Insecticidas
--3 Siembra
--10 Tratamiento de semilla
--9 Fungicidas
--/////////////////////////////////////////////
--@id_grano
--1 Trigo
--2 Cebada
--3 Girasol
--4 Sorgo
--5 Soja 1°
--6 Soja 2°
--7 Maíz 1° Temprano
--8 Maíz 1° Tardio y 2°
--/////////////////////////////////////////////
--@id_nivel
--1 Alto
--2 Medio
--3 Bajo
--/////////////////////////////////////////////
--@id_zona
--1 I NOA
--2 IIe NEA Este (Chaco y Formosa)
--3 III Ctro N Cba
--4 IV S Cba
--5 Vc Ctro N SFe
--6 VI Núcleo Norte
--7 VII Núcleo Sur
--8 VIII Ctro E ER
--9 IX N LP-OBA
--10 X Ctro BA
--11 XI SO BA-S LP
--12 XII SE BA
--13 XIII San Luis
--14 XIV Cuenca Sal
--15 XV Corrientes-Misiones
--16 IIo NEA Oeste (este de Sgo. del Estero)
--17 Vn Norte SFe
--/////////////////////////////////////////////
--@id_campaña
--1 2010/2011
--2 2011/2012
--3 2012/2013
--4 2013/2014
--5 2014/2015
--6 2015/2016
--7 2016/2017
--8 2017/2018
--9 2018/2019
--10 2019/2020
declare @id_campaña int
declare @id_consulta int
declare @id_grano int
declare @id_nivel int
declare @id_zona int
set @id_campaña= 9 -- 2018/2019
set @id_consulta= 6--Fertilización
set @id_grano = 1 --Trigo
set @id_nivel= 1 -- nivel 1
set @id_zona = 5 -- Vc Ctro N SFe
SELECT (SELECT descripcion
FROM Tipo_promedios
WHERE (id = 1)) AS des_prom, 1 AS tipo_promedio, xx.id, xx.id_grano,
gg.descripcion AS des_grano, cc.id_tipo_pregunta, cc.id_caract,
cc.descripcion AS des_caract, nn.descripcion AS des_nivel, xx.id_nivel,
xx.id_zona, zz.descripcion AS Expr1, zz.descripcion2,
CAST(ISNULL((SELECT SUM(max) / COUNT(1) AS Expr1
FROM(SELECT ISNULL(t.max, 0) AS max
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.max IS NOT NULL) AND (t.id_grano = xx.id_grano) AND
(t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
(SELECT c.id_tipo_pregunta FROM tipo_pregunta_retaa AS
p LEFT OUTER JOIN Tipo_caracteristicas_retaa AS
c ON p.id = c.id_tipo_pregunta WHERE (p.id_filtro IN
(cc.id_tipo_pregunta)) AND (c.id_grano = xx.id_grano)
GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.max_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2), 0) AS DECIMAL(10, 2)) AS Alto_Promedio_max, 'http://bc-sellos/PruebaRetaa/pop_up_X_rubros.aspx?par=' + CAST(@id_campaña AS nvarchar(1))
+ ';' + CAST(xx.id_grano AS nvarchar(2)) + ';' + CAST(xx.id_zona AS nvarchar(2)) + ';' + CAST(cc.id_tipo_pregunta AS nvarchar(2)) + ';' + CAST(cc.id_caract_2 AS nvarchar(3)) + ';' + CAST(xx.id_nivel AS nvarchar(3)) + ';' + '0' AS URL,
CAST(ISNULL
((SELECT SUM(min) / COUNT(1) AS Expr1
FROM (SELECT ISNULL(t.min, 0) AS min
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.min IS NOT NULL) AND (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
(SELECT c.id_tipo_pregunta
FROM tipo_pregunta_retaa AS p LEFT OUTER JOIN
Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
WHERE (p.id_filtro = cc.id_tipo_pregunta) AND (c.id_grano = xx.id_grano)
GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.min_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_7
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1), 0) AS DECIMAL(10, 2)) AS Alto_Promedio_min, ISNULL
((SELECT SUM(max_null) / COUNT(1) AS Expr1
FROM (SELECT (CASE WHEN porc_aplic IS NULL THEN ISNULL(t .max, 0) ELSE ISNULL(t .max, 0) * porc_aplic / 100 END) AS max_null
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
(SELECT c.id_tipo_pregunta
FROM tipo_pregunta_retaa AS p LEFT OUTER JOIN
Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
WHERE (p.id_filtro = cc.id_tipo_pregunta) AND (c.id_grano = xx.id_grano)
GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.max_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_6
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS gg_1), 0) AS Alto_Promedio_max_null, ISNULL
((SELECT SUM(max_null) / COUNT(1) AS Expr1
FROM (SELECT (CASE WHEN porc_aplic IS NULL THEN ISNULL(t .min, 0) ELSE ISNULL(t .min, 0) * porc_aplic / 100 END) AS max_null
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
(SELECT c.id_tipo_pregunta
FROM tipo_pregunta_retaa AS p LEFT OUTER JOIN
Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
WHERE (p.id_filtro = cc.id_tipo_pregunta) AND (c.id_grano = xx.id_grano)
GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.min_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_5
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS gg_1_1), 0) AS Alto_Promedio_min_null, cc.id_indice,
(SELECT descripcion
FROM tipo_pregunta_retaa
WHERE (id =
(SELECT id_filtro
FROM tipo_pregunta_retaa AS tipo_pregunta_retaa_3
WHERE (id IN (cc.id_tipo_pregunta))))) AS des_consulta, CAST
(((SELECT SUM(max) / COUNT(1) AS Expr1
FROM (SELECT ISNULL(t.max, 0) AS max
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta =
(SELECT TOP (1) id_tipo_pregunta
FROM caract_id_grano AS caract_id_grano_2
WHERE (id_caract = gg.id_filtro_caract))) AND (t.nivel = 1) AND (t.id_caract = gg.id_filtro_caract) AND (t.max_estado = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_2
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_2) +
(SELECT SUM(min) / COUNT(1) AS Expr1
FROM (SELECT ISNULL(t.min, 0) AS min
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta =
(SELECT TOP (1) id_tipo_pregunta
FROM caract_id_grano AS caract_id_grano_1
WHERE (id_caract = gg.id_filtro_caract))) AND (t.nivel = 1) AND (t.id_caract = gg.id_filtro_caract) AND (t.min_estado = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_1
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_1_1)) / 2 / 100 *
(SELECT superficie
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_1
WHERE (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) AS DECIMAL(10, 0)) AS superficie_2, CAST
((SELECT superficie
FROM Superficie_retaa_x_campaña_grano
WHERE (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) AS DECIMAL(10, 0)) AS superficie, zz.indice,
(SELECT SUM(max) / COUNT(1) AS Expr1
FROM (SELECT ISNULL(t.max, 0) AS max
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta = 2) AND (t.nivel = xx.id_nivel) AND (t.id_caract = 4) AND (t.max_estado = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_4
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_1) AS Alto_Promedio_max_distribucion,
(SELECT SUM(max) / COUNT(1) AS Expr1
FROM (SELECT ISNULL(t.max, 0) AS max
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano IN
(SELECT ID_MAPA
FROM Tipo_grano_reportes
WHERE (id = gg.id_grano_report))) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta =
(SELECT TOP (1) id_tipo_pregunta
FROM caract_id_grano AS caract_id_grano_2
WHERE (id_caract = gg.id_filtro_caract))) AND (t.nivel = 1) AND (t.id_caract = gg.id_filtro_caract) AND (t.max_estado = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_2
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_2_1) *
(SELECT superficie
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_1
WHERE (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) / 100 AS superficie_3,
(SELECT primera
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_2
WHERE (id_grano =
(SELECT id_grano_report
FROM Tipo_grano AS Tipo_grano_2
WHERE (id = xx.id_grano))) AND (id_campaña = @id_campaña) AND (id_zona = xx.id_zona)) *
(SELECT superficie
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_3
WHERE (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) / 100 AS Pas_primera_superficie,
(SELECT segunda
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_1
WHERE (id_grano =
(SELECT id_grano_report
FROM Tipo_grano AS Tipo_grano_1
WHERE (id = xx.id_grano))) AND (id_campaña = @id_campaña) AND (id_zona = xx.id_zona)) *
(SELECT superficie
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_4
WHERE (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) / 100 AS pas_segunda_superficie, cc.tipo_unidad, CASE WHEN cc.id_tipo_pregunta = 7 OR
cc.id_tipo_pregunta = 6 THEN
(SELECT TOP (1) Coeficiente
FROM Tipo_caracteristicas_retaa
WHERE id_caract = cc.id_caract) ELSE '-1' END AS coeficiente, l.descripcion AS campaña
FROM Granos_zonas_retaa AS xx LEFT OUTER JOIN
Tipo_zona_retaa AS zz ON xx.id_zona = zz.id_zona LEFT OUTER JOIN
Tipo_nivel AS nn ON xx.id_nivel = nn.id_nivel LEFT OUTER JOIN
Tipo_grano AS gg ON xx.id_grano = gg.id LEFT OUTER JOIN
Tipo_caracteristicas_retaa AS cc ON xx.id_grano = cc.id_grano AND cc.id_tipo_pregunta IN
(SELECT c.id_tipo_pregunta
FROM tipo_pregunta_retaa AS p LEFT OUTER JOIN
Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
WHERE (p.id_filtro IN (@id_consulta)) AND (c.id_grano = xx.id_grano)
GROUP BY c.id_tipo_pregunta) LEFT OUTER JOIN
Año_campañas AS l ON cc.id_campaña = l.id
WHERE (xx.id_grano IN (@id_grano)) AND (xx.id_zona IN (@id_zona)) AND (xx.id_nivel IN (@id_nivel)) AND (cc.id_caract_2 <> 104) AND (cc.id_caract_2 <> 105) AND (cc.id_caract_2 <> 106) AND (cc.id_caract_2 <> 107) AND (cc.id_caract_2 <> 108) AND
(cc.id_caract_2 <> 65) AND (cc.id_campaña = @id_campaña);")
consulta_Ruben
Paquete DBI
DBI permite conectarno a la base de datos de SQL. Para hacerlo debemos configurar los campos. La conexión se puede verificar en el panel superior derecho.
La base datos del ReTAA esta compuesta por 6 tablas principales “Año Campañas”, “cabecera_trnsacciones_retaa”, “caract_id_grano”, “caract_id_grano_campaña_vista”, “Colaboradores” y “Granos_zonas_retaa”.
#Me conecto a la base
con <- DBI::dbConnect(odbc::odbc(),
Driver = "SQL Server",
Server = "BC-RETA",
Database = "Estimaciones_copia",
UID = "estimaciones_consulta",
PWD = "Esti.bc.201923",
Port = 1433,
dbname = "Estimaciones_Copia",
encoding = "latin1")
DBI::dbListTables(con)[1:6]#lista de las tablas de la base
[1] "Año_campañas" "cabecera_transacciones_retaa"
[3] "caract_id_grano" "caract_id_grano_campaña_vista"
[5] "Colaboradores" "Granos_zonas_retaa"
la función tbl de dplyr trae las tablas de la base de datos. Tambien podemos aplicar a esta tabla todas las funciones que vimos en las clases previas.
Veamos algunas de las tablas que conforman la base del ReTAA.
Tabla Tipo_grano
#Tabla id grano
Tipo_grano <- tbl(con, c("Tipo_grano")) %>%
select(id,descripcion) %>% rename(id_grano = id, descripcion_grano = descripcion) %>% filter(id_grano>0)
Tipo_grano
Tabla Año_campañas
#selecciono tabla id campaña
Anio_campanias <- tbl(con, c("Año_campañas")) %>% rename(id_campania = id, descripcion_campania = descripcion) %>% filter(id_campania>0)
Anio_campanias
Tabla Tipo_zona_retaa
#cabecera_transacciones_retaa
Tipo_zona_retaa <- tbl(con, c("Tipo_zona_retaa")) %>% select(id_zona,descripcion,descripcion2) %>% rename(descripcion_zona_retaa = descripcion,
descripcion_zona_retaa2 = descripcion2)
Tipo_zona_retaa %>% head(10)
Tabla cabecera_transacciones_retaa
#cabecera_transacciones_retaa
cabecera_transacciones_retaa <- tbl(con, c("cabecera_transacciones_retaa")) %>% select(id_trans,id_colaborador,estado)
cabecera_transacciones_retaa %>% head(10)
Tabla tipo_pregunta_retaa
#cabecera_transacciones_retaa
tipo_pregunta_retaa <- tbl(con, c("tipo_pregunta_retaa")) %>%
select(id,descripcion) %>% rename(id_pregunta = id, descripcion_pregunta = descripcion) %>% as_tibble()
tipo_pregunta_retaa
Tabla tipo_caracteristica_retaa
#cabecera_transacciones_retaa
Tipo_caracteristicas_retaa <- tbl(con, c("Tipo_caracteristicas_retaa_trans"))
Tipo_caracteristicas_retaa
Tabla Colaboradores
#Tabla Colaboradores
Colaboradores <- tbl(con, c("Colaboradores"))
Colaboradores %>% variable.names()
[1] "id_colaborador" "id_Zona" "id_semana" "fec_alta" "Empresa"
[6] "Nombre" "Apellido" "Localidad" "Provincia" "Telefono"
[11] "Celular" "e_mail" "obs" "poligono" "id_usuario"
[16] "fec_ultimaMod" "id_usuarioMod" "Emp_vinculada" "estado" "direccion"
[21] "cp" "dto" "localidad1" "tipo_nivel" "id_zona_retaa"
[26] "id_estado_retaa" "obs_retaa" "latitud" "logitud"
Tambien podemos visualizar las conexxiones entre las tablas con el paquete datamodelr que nos permite construir diagramas entidad-realación
library(datamodelr) #paquete para armar diagrama de entidad relacion
coneccion <- odbcDriverConnect(
connection = "Driver=SQL Server; Server=BC-RETA; Database=Estimaciones_copia; UID=estimaciones_consulta; Pwd=Esti.bc.201923"
)
sQuery <- dm_re_query("sqlserver")
dm_retaa <- sqlQuery(channel = coneccion, sQuery, stringsAsFactors = FALSE, errors=TRUE)
dm_retaa <- as.data_model(dm_retaa) #paso a formato modelo
focus <-list(tables = c("Año_campañas","cabecera_transacciones_retaa","caract_id_grano",
"caract_id_grano_campaña_vista","Colaboradores","Granos_zonas_retaa"))
graph <- dm_create_graph(dm_retaa , rankdir = "BT", focus = focus, col_attr = c("column", "type"))
dm_render_graph(graph) #grafico
Registered S3 methods overwritten by 'htmltools':
method from
print.html tools:rstudio
print.shiny.tag tools:rstudio
print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
Query SQL vs dplyr
En esta seccion vamos a replicar la consulta SQL que vimos arriba pero en fomrato dplyr. Vamos a ver que una consulta muy extensa se puede realizar en una fomra más prolija y breve.
El comandoshow_query permite extraer la consulta en formato SQL.
tabla_consulta_sql <- Tipo_caracteristicas_retaa %>%
left_join(cabecera_transacciones_retaa,by = c("id_trans","id_colaborador")) %>% #join con tabla cabecera
left_join(Tipo_grano ,by = "id_grano") %>%
left_join(Anio_campanias ,by = c("id_campaña"="id_campania") ) %>%
left_join(Tipo_zona_retaa, by = c("id_zona") ) %>%
filter(id_campaña == 9,id_zona==5,nivel==1,id_grano==1,
id_tipo_pregunta==6, max_estado == 1, estado==1) %>%
group_by(descripcion_grano, id_grano, descripcion_campania, id_campaña, descripcion_zona_retaa, id_zona,
nivel, id_tipo_pregunta, id_caract,descripcion) %>%
summarise(promedio_max = round(mean(max, na.rm = T),2),
promedio_min = round(mean(min, na.rm = T),2))
tabla_consulta_sql %>% dplyr::show_query() #ver query SQL
<SQL>
SELECT "descripcion_grano", "id_grano", "descripcion_campania", "id_campaña", "descripcion_zona_retaa", "id_zona", "nivel", "id_tipo_pregunta", "id_caract", "descripcion", ROUND(AVG("max"), 2) AS "promedio_max", ROUND(AVG("min"), 2) AS "promedio_min"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "LHS"."estado" AS "estado", "LHS"."descripcion_grano" AS "descripcion_grano", "LHS"."descripcion_campania" AS "descripcion_campania", "RHS"."descripcion_zona_retaa" AS "descripcion_zona_retaa", "RHS"."descripcion_zona_retaa2" AS "descripcion_zona_retaa2"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "LHS"."estado" AS "estado", "LHS"."descripcion_grano" AS "descripcion_grano", "RHS"."descripcion_campania" AS "descripcion_campania"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "LHS"."estado" AS "estado", "RHS"."descripcion_grano" AS "descripcion_grano"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "RHS"."estado" AS "estado"
FROM "Tipo_caracteristicas_retaa_trans" AS "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT "id_trans", "id_colaborador", "estado"
FROM "cabecera_transacciones_retaa") "RHS"
ON ("LHS"."id_trans" = "RHS"."id_trans" AND "LHS"."id_colaborador" = "RHS"."id_colaborador")
) "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT *
FROM (SELECT TOP 100 PERCENT "id" AS "id_grano", "descripcion" AS "descripcion_grano"
FROM "Tipo_grano") "dbplyr_003"
WHERE ("id_grano" > 0.0)) "RHS"
ON ("LHS"."id_grano" = "RHS"."id_grano")
) "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT *
FROM (SELECT TOP 100 PERCENT "id" AS "id_campania", "descripcion" AS "descripcion_campania"
FROM "Año_campañas") "dbplyr_004"
WHERE ("id_campania" > 0.0)) "RHS"
ON ("LHS"."id_campaña" = "RHS"."id_campania")
) "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT "id_zona", "descripcion" AS "descripcion_zona_retaa", "descripcion2" AS "descripcion_zona_retaa2"
FROM "Tipo_zona_retaa") "RHS"
ON ("LHS"."id_zona" = "RHS"."id_zona")
) "dbplyr_005"
WHERE (("id_campaña" = 9.0) AND ("id_zona" = 5.0) AND ("nivel" = 1.0) AND ("id_grano" = 1.0) AND ("id_tipo_pregunta" = 6.0) AND ("max_estado" = 1.0) AND ("estado" = 1.0))
GROUP BY "descripcion_grano", "id_grano", "descripcion_campania", "id_campaña", "descripcion_zona_retaa", "id_zona", "nivel", "id_tipo_pregunta", "id_caract", "descripcion"
tabla_consulta_sql #salida
Planteos Tecnologicos
Construir los planteos tecnológicos suele ser un trabajo que tedioso que no esta automatizado y suele tomar bastante tiempo. En esta sección buscamos automatizar la construcción de los planteos.
# tabla con todas los insumos incluidos en la base
tabla_variables <- Tipo_caracteristicas_retaa %>% distinct(descripcion,tipo_unidad) %>% as_tibble()
#lista de variables incluidas
variables_planteo <- c("Adopción de NT","max_min","nivel","id_campaña","id_grano","id_zona",
"descr_grano","descr_campania","Semilla","Urea","PDA",
"Glifosato concentrado - Barbecho",
"Glifosato concentrado - cultivo","Hib. RR Bt2","2-4D","Dicamba",
"Metsulfurón",
"SPS","Atrazina","Metolaclor","Piclorám","Diamidas","Diclosulam",
"Fungicida 1 (Estrob. + Triazol)","Semilla", "Inoc. + Fungic.",
"Inoculante 1 (full)","Fosforados 1", "Fosforados 2",
"Curasemilla - Fungicida base","Clorimurón",
"PMA","Dimetoato", "Curasemilla 2 - Fungicida",
"Curasemilla 2 - fungic.","
Fungicida 2")
#Armo la consulta de planteos
planteos <- Tipo_caracteristicas_retaa %>%
filter(descripcion %in% variables_planteo) %>% #me quedo con insumos incluidos en los planteos
left_join(cabecera_transacciones_retaa, by = c("id_trans","id_colaborador")) %>%
left_join(Tipo_zona_retaa, by=c("id_zona")) %>%
left_join(Tipo_grano, by="id_grano") %>%
#left_join(tipo_pregunta_retaa, by = c("id_tipo_pregunta"= "id_pregunta")) %>%
left_join(Anio_campanias,by=c("id_campaña"="id_campania" )) %>%
filter(estado==1) %>% #encuestas validadas
#correcion maiz tardio por carga retaa
mutate(id_grano = case_when( (id_grano==8 & id_zona %in% c(1,2,16) )~ 7,
T ~ as.double(id_grano) ),
descripcion_grano = ifelse(id_grano==7, "Maíz 1° Temprano",descripcion_grano)
) %>%
mutate(max = case_when(tipo_unidad =="%" & is.na(max) ~ 0,
T ~ as.numeric(max) ),
min = case_when(tipo_unidad =="%" & is.na(min) ~ as.numeric(max),
T ~ as.numeric(min)
)
) %>%
group_by( id_campaña ,descripcion_campania , nivel,
id_zona, descripcion_zona_retaa,
id_grano, descripcion_grano, descripcion) %>%
summarise(promedio_max = mean(max, na.rm = T), #promedio maximo aplicado
promedio_min = mean(min, na.rm = T) #promedio minimo aplicado
#promedio_porc_aplic = mean(porc_aplic, na.rm = T)
) %>%
mutate(doble_na = ifelse( is.na(promedio_max) & is.na(promedio_min),1,0 )) %>%
filter(doble_na !=1) %>%
mutate( promedio = (promedio_max+ promedio_min)/2) %>%
select(-c(promedio_max,promedio_min) )
#Funcion para escalar el nivel de adopcion tecnologica
#escalar <- function(x){ x = x/sum(x,na.rm = T) *100 }
#Genero descripcion Nivel Tecnológico y escalo Adopcion de NT
planteos <- planteos %>% as_tibble() %>%
mutate(descripcion_nivel = case_when(nivel == 1 ~ "Alto",
nivel == 2 ~ "Medio",
nivel == 3 ~ "Bajo")) %>%
pivot_wider(names_from = descripcion,values_from = c(promedio) ) %>%
group_by(id_campaña,id_zona,id_grano)# %>%
#mutate(Adopcion_NT = escalar(`Adopción de NT`)) #escalo a 100 el nivel tecnologico
#Paso a formato long
planteos <- planteos %>%
mutate(adopcion_nt = `Adopción de NT`) %>%
pivot_longer(cols = -c("id_campaña", "descripcion_campania","nivel","id_zona","descripcion_zona_retaa" ,"id_grano","descripcion_grano", "descripcion_nivel","adopcion_nt") ,names_to = "variables",values_to = "valores")
Tipo_zona_retaa
planteos_pond <- planteos %>%
group_by(id_campaña,descripcion_campania,id_zona, descripcion_zona_retaa,
id_grano,descripcion_grano,variables) %>%
filter(!is.na(valores) ) %>% #esto es para no contar los no contestados y calcular los planteos Retaa "promedio simple"
summarise(valores = weighted.mean(valores ,w = adopcion_nt/100,na.rm = T)
)
Planteos
Soja
variables_planteo_soja <-c("Semilla", "SPS","Glifosato concentrado - Barbecho",
"Glifosato concentrado - cultivo", "2-4D","Clorimurón",
"Metsulfurón","Diclosulam","Diamidas",
"Estrobirulina + Triazol","Inoculante 1 (full)","Inoc. + Fungic.","Fungicida 2")
planteo_soja <- planteos_pond %>%
filter(descripcion_grano=="Soja 1°",variables %in% variables_planteo_soja) %>% ungroup()
planteos_pond %>%
filter(descripcion_grano=="Soja 1°",variables %in% variables_planteo_soja) %>%
ggplot(.,mapping = aes(y=valores,x=descripcion_campania, color=as.factor(descripcion_zona_retaa)))+
geom_point() + facet_wrap(~variables, scales = "free_y")+
labs(title = "Dosis aplicadas - Soja 1º")+
labs(x="Campaña", color="Zona")+
theme(axis.text.x = element_text(angle = 90),
legend.position = "bottom"
)

planteos %>%
filter(descripcion_grano=="Soja 1°",variables %in% variables_planteo_soja) %>%
filter(descripcion_campania=="2017/2018",descripcion_zona_retaa=="III")
planteos %>% filter(variables=="Adopción de NT") %>% group_by(id_grano, descripcion_grano, descripcion_zona_retaa,descripcion_campania) %>% summarise(adopcion = sum(valores))
planteos %>% filter(descripcion_campania=="2016/2017", descripcion_zona_retaa=="III",
id_grano==2, variables=="Adopción de NT")
Trigo
variables_planteo_Trigo <-c("Semilla","Urea","PMA","Glifosato concentrado - Barbecho",
"2-4D","Dicamba", "Metsulfurón","Fosforados 1","Fungicida 1 (Estrob. + Triazol)",
"Curasemilla 2 - Fungicida","Curasemilla 2 - fungic.") #Lambdacialotrina no lo encontré
planteo_trigo <- planteos_pond %>%
filter(descripcion_grano=="Trigo",variables %in% variables_planteo_Trigo) %>% ungroup()
planteos_pond %>%
filter(descripcion_grano=="Trigo",variables %in% variables_planteo_Trigo) %>%
ggplot(.,mapping = aes(y=valores,x=descripcion_campania, color=as.factor(descripcion_zona_retaa)))+
geom_point() + facet_wrap(~variables, scales = "free_y")+
labs(title = "Dosis aplicadas - Trigo")+
labs(x="Campaña", color="Zona")+
theme(axis.text.x = element_text(angle = 90),
legend.position = "bottom"
)

Maiz
variables_planteo_Maiz <-c( "Hib. RR Bt2", "Urea","PDA","Glifosato concentrado - Barbecho",
"Glifosato concentrado - cultivo", "2-4D","Atrazina",
"Metolaclor","Piclorám","Diamidas",
"Dicamba", "Estrobirulina + Triazol") #Lambdacialotrina no lo encontré
planteo_maiz <- planteos_pond %>%
filter(descripcion_grano=="Maíz 1° Temprano",variables %in% variables_planteo_Maiz) %>% ungroup()
planteos_pond %>%
filter(descripcion_grano=="Maíz 1° Temprano",variables %in% variables_planteo_Maiz) %>%
ggplot(.,mapping = aes(y=valores,x=descripcion_campania, color=as.factor(descripcion_zona_retaa)))+
geom_point() + facet_wrap(~variables, scales = "free_y")+
labs(title = "Dosis aplicadas - Maiz")+
labs(x="Campaña", color="Zona")+
theme(axis.text.x = element_text(angle = 90),
legend.position = "bottom"
)

Guardo planteos
library(openxlsx) #activamos la librería
write.xlsx(x = planteos_pond, file = "datasets/planteos.xlsx", row.names = FALSE)
Evolución del nivel tecnológico
Maiz 1º
planteos %>% filter(descripcion_grano=="Maíz 1° Temprano", variables=="Adopción de NT") %>%
ggplot(.,mapping = aes(x = descripcion_campania, y = valores, group=nivel,fill = as.factor(descripcion_nivel))) +
geom_col() +
facet_wrap(~descripcion_zona_retaa)+ theme_bw()+
labs(title = "Nivel tecnológico por zona - Maíz temprano")+
labs(x="Campaña", fill="Nivel tecnológico")+
theme(axis.text.x = element_text(angle = 90),
legend.position = "top"
)

Maiz Tardio y 2º

Soja
planteos %>% filter(descripcion_grano=="Soja 1°", variables=="Adopción de NT") %>%
ggplot(.,mapping = aes(x = descripcion_campania, y = valores, group=nivel,fill = as.factor(descripcion_nivel))) +
geom_col() +
facet_wrap(~descripcion_zona_retaa)+ theme_bw()+
labs(title = "Nivel tecnológico por zona -Soja")+
labs(x="Campaña", fill="Nivel tecnológico")+
theme(axis.text.x = element_text(angle = 90),
legend.position = "top"
)

Trigo
planteos %>% filter(descripcion_grano=="Trigo" , variables=="Adopción de NT") %>%
ggplot(.,mapping = aes(x = descripcion_campania, y = valores, group=nivel,fill = as.factor(descripcion_nivel))) +
geom_col() +
facet_wrap(~descripcion_zona_retaa)+ theme_bw()+
labs(title = "Nivel tecnológico por zona -Trigo")+
labs(x="Campaña", fill="Nivel tecnológico")+
theme(axis.text.x = element_text(angle = 90),
legend.position = "top"
)

Girasol

Cebada

Dosis de fertilización
#Grafico
planteos %>% filter(descripcion_grano=="Maíz 1° Temprano", variables=="Urea") %>% #filtro cultivo
ggplot(.,mapping = aes(x = descripcion_campania,
y = valores, group=nivel,color = as.factor(descripcion_nivel))) +
geom_line() + geom_point()+
facet_wrap(~descripcion_zona_retaa) +
theme_bw() +
labs(title = "Fertilización con Urea (kg/ha) en Maíz temprano")+
labs(x="Campaña", color="Nivel tecnológico")+
theme(axis.text.x = element_text(angle = 90),
legend.position = "bottom"
)

#Grafico
planteos_pond %>% filter(descripcion_grano=="Maíz 1° Temprano", variables=="Urea") %>% #filtro cultivo
ggplot(.,mapping = aes(x = descripcion_campania,
y = valores, group=1)) +
geom_line() + geom_point()+
facet_wrap(~descripcion_zona_retaa) +
theme_bw() +
labs(title = "Fertilización con Urea (kg/ha) en Maíz temprano")+
labs(x="Campaña", color="Nivel tecnológico")+
theme(axis.text.x = element_text(angle = 90),
legend.position = "bottom"
)

#Grafico
planteos_pond %>% filter(descripcion_grano=="Trigo", variables=="Urea") %>% #filtro cultivo
ggplot(.,mapping = aes(x = descripcion_campania,
y = valores, group=1)) +
geom_line() + geom_point()+
facet_wrap(~descripcion_zona_retaa) +
theme_bw() +
labs(title = "Fertilización con Urea (kg/ha) en Trigo")+
labs(x="Campaña", color="Nivel tecnológico")+
theme(axis.text.x = element_text(angle = 90),
legend.position = "bottom"
)

Precios
https://emoriebeck.github.io/R-tutorials/purrr/#
unique(planteos$variables)
[1] "doble_na" "2-4D"
[3] "PDA" "Semilla"
[5] "Fosforados 2" "Atrazina"
[7] "Hib. RR Bt2" "Dicamba"
[9] "Fosforados 1" "Adopción de NT"
[11] "Curasemilla 2 - Fungicida" "Inoculante 1 (full)"
[13] "Metsulfurón" "SPS"
[15] "Clorimurón" "Urea"
[17] "PMA" "Fungicida 1 (Estrob. + Triazol)"
[19] "Inoc. + Fungic." "Diamidas"
[21] "Diclosulam" "Metolaclor"
[23] "Curasemilla 2 - fungic." "Piclorám"
[25] "Glifosato concentrado - Barbecho" "Glifosato concentrado - cultivo"
[27] "Curasemilla - Fungicida base"
LS0tDQp0aXRsZTogQmFzZXMgU1FMIGVuIFINCnN1YnRpdGxlOiBJbnRyb2R1Y2Npw7NuDQpkYXRlOiAiIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KLS0tDQoNClIgY3VlbnRhIGNvbiB2YXJpb3MgcGFxdWV0ZXMgZGUgZnVuY2lvbmVzIHF1ZSBwZXJtaXRlbiB0cmFiYWphciBjb24gYmFzZXMgU1FMIGNvbiBmYWNpbGlkYWQuIEEgY29udGludWFjacOzbiB2YW1vcyBhIHZlciBhbGd1bmFzIGhlcnJhbWllbnRhcyB5IGVqZW1wbG9zIGRlIGNvbW8gdHJhYmFqYXIgbGFzIGJhc2VzIGRlIGRhdG9zIGRlIGxhIEJkZUMgY29uIFIuDQoNCg0KIyMjIFBhcXVldGVzDQoNCkhheSBkb3MgcGFxdWV0ZXMgw7p0aWxlcyBwYXJhIHRyYWJhamFyIGJhc2VzIFNRTCBgREJJYCB5IGBST0RCQ2AuIEFzaW1pc21vLCBgZHBseXJgIGN1ZW50YSBjb24gZnVuY2lvbmVzIHF1ZSBwZXJtaXRlbiBleHBvcnRhciBsYXMgY29uc3VsdGFzIGEgZm9ybWF0byBTUUwuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KFJPREJDKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRicGx5cikNCmBgYA0KDQojIyMgQ29uZXhpw7NuIGEgbGEgYmFzZSB5IGNvbnN1bHRhcw0KDQpNZSBjb25lY3RvIGEgbGEgYmFzZSBjb24gbGEgZnVuY2lvbiBvZGJjRHJpdmVyQ29ubmVjdC4NCg0KYGBge3J9DQpjaCA8LSBvZGJjRHJpdmVyQ29ubmVjdCgNCiAgY29ubmVjdGlvbiA9ICJEcml2ZXI9U1FMIFNlcnZlcjsgU2VydmVyPUJDLVJFVEE7DQogICAgICAgICAgICAgICAgRGF0YWJhc2U9RXN0aW1hY2lvbmVzX2NvcGlhOw0KICAgICAgICAgICAgICAgIFVJRD1lc3RpbWFjaW9uZXNfY29uc3VsdGE7DQogICAgICAgICAgICAgICAgUHdkPUVzdGkuYmMuMjAxOTIzIg0KICApDQoNCmBgYA0KDQoNCiMjIyBDb25zdWx0YSBTUUwNCg0Kc3FsUXVlcnkgcGVybWl0ZSB1dGlsaXphciBlbCBjb2RpZ28gZGUgc3FsIGVuIFIuIExhIGNvbnN1bHRhIHNlIGluc2VydGEgY29tbyBzdHJpbmcuDQoNCkVuIGVzdGEgY29uc3VsdGEgc2VsZWNjaW9uYW1vcyBzZSBjb21iaW5hbiA1IHRhYmxhcyB5IHNlIHNlbGVjY2lvbmEgcGFyYSBlbCBjdWx0aXZvIHRyaWdvLCBlbiBsYSBjYW1wYcOxYSAxOC8xOSwgIGVuIGVsIG5pdmVsIHRlY25vbG9naWNvIGFsdG8sIGVuIGxhIHpvbmEgUmV0YWEgNSBsYXMgZG9zaXMgZGUgZmVydGlsaXphY2lvbiBwcm9tZWRpby4NCg0KYGBge3IsIGVjaG89VH0NCmNvbnN1bHRhX1J1YmVuIDwtIHNxbFF1ZXJ5KGNoYW5uZWwgPSBjaCwgcXVlcnkgPSAiLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX2NvbnN1bHRhDQotLTYJRmVydGlsaXphY2nDs24NCi0tNwlIZXJiaWNpZGFzDQotLTgJSW5zZWN0aWNpZGFzDQotLTMJU2llbWJyYQ0KLS0xMCBUcmF0YW1pZW50byBkZSBzZW1pbGxhDQotLTkJRnVuZ2ljaWRhcw0KLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX2dyYW5vDQotLTEJVHJpZ28NCi0tMglDZWJhZGENCi0tMwlHaXJhc29sDQotLTQJU29yZ28NCi0tNQlTb2phIDHCsA0KLS02CVNvamEgMsKwDQotLTcJTWHDrXogMcKwIFRlbXByYW5vDQotLTgJTWHDrXogMcKwIFRhcmRpbyB5IDLCsA0KLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX25pdmVsDQotLTEJQWx0bw0KLS0yCU1lZGlvDQotLTMJQmFqbw0KLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX3pvbmENCi0tMQkgICAgSQlOT0ENCi0tMgkgICAgSUllCU5FQSBFc3RlIChDaGFjbyB5IEZvcm1vc2EpDQotLTMJICAgIElJSQlDdHJvIE4gQ2JhDQotLTQJICAgIElWCVMgQ2JhDQotLTUJICAgIFZjCUN0cm8gTiBTRmUNCi0tNgkgICAgVkkJTsO6Y2xlbyBOb3J0ZQ0KLS03CSAgICBWSUkJTsO6Y2xlbyBTdXINCi0tOAkgICAgVklJSQlDdHJvIEUgRVINCi0tOQkgICAgSVgJTiBMUC1PQkENCi0tMTAJWAlDdHJvIEJBDQotLTExCVhJCVNPIEJBLVMgTFANCi0tMTIJWElJCVNFIEJBDQotLTEzCVhJSUkJU2FuIEx1aXMNCi0tMTQJWElWCUN1ZW5jYSBTYWwNCi0tMTUJWFYJQ29ycmllbnRlcy1NaXNpb25lcw0KLS0xNglJSW8JTkVBIE9lc3RlIChlc3RlIGRlIFNnby4gZGVsIEVzdGVybykNCi0tMTcJVm4JTm9ydGUgU0ZlDQotLS8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLw0KLS1AaWRfY2FtcGHDsWENCi0tMQkgMjAxMC8yMDExDQotLTIJIDIwMTEvMjAxMg0KLS0zCSAyMDEyLzIwMTMNCi0tNAkgMjAxMy8yMDE0DQotLTUJIDIwMTQvMjAxNQ0KLS02CSAyMDE1LzIwMTYNCi0tNwkgMjAxNi8yMDE3DQotLTgJIDIwMTcvMjAxOA0KLS05CSAyMDE4LzIwMTkNCi0tMTAgMjAxOS8yMDIwDQoNCmRlY2xhcmUgQGlkX2NhbXBhw7FhIGludA0KZGVjbGFyZSBAaWRfY29uc3VsdGEgaW50DQpkZWNsYXJlIEBpZF9ncmFubyBpbnQNCmRlY2xhcmUgQGlkX25pdmVsIGludA0KZGVjbGFyZSBAaWRfem9uYSBpbnQNCg0Kc2V0IEBpZF9jYW1wYcOxYT0gOSAtLSAyMDE4LzIwMTkNCnNldCBAaWRfY29uc3VsdGE9IDYtLUZlcnRpbGl6YWNpw7NuDQpzZXQgQGlkX2dyYW5vID0gMSAtLVRyaWdvDQpzZXQgQGlkX25pdmVsPSAxIC0tIG5pdmVsIDENCnNldCBAaWRfem9uYSA9IDUgLS0gVmMJQ3RybyBOIFNGZSANCg0KU0VMRUNUIChTRUxFQ1QgZGVzY3JpcGNpb24NCiAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX3Byb21lZGlvcw0KICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWQgPSAxKSkgQVMgZGVzX3Byb20sIDEgQVMgdGlwb19wcm9tZWRpbywgeHguaWQsIHh4LmlkX2dyYW5vLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBnZy5kZXNjcmlwY2lvbiBBUyBkZXNfZ3Jhbm8sIGNjLmlkX3RpcG9fcHJlZ3VudGEsIGNjLmlkX2NhcmFjdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2MuZGVzY3JpcGNpb24gQVMgZGVzX2NhcmFjdCwgbm4uZGVzY3JpcGNpb24gQVMgZGVzX25pdmVsLCB4eC5pZF9uaXZlbCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeHguaWRfem9uYSwgenouZGVzY3JpcGNpb24gQVMgRXhwcjEsIHp6LmRlc2NyaXBjaW9uMiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgQ0FTVChJU05VTEwoKFNFTEVDVCBTVU0obWF4KSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgIEZST00oU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjIE9OIGMuaWRfdHJhbnMgPSB0LmlkX3RyYW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHQubWF4IElTIE5PVCBOVUxMKSBBTkQgKHQuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykgQU5EDQogICAgICAgICAgICAgICAgICAgICAgICAgICh0LmlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSBBTkQgKHQuaWRfdGlwb19wcmVndW50YSBJTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGMuaWRfdGlwb19wcmVndW50YSAgRlJPTSB0aXBvX3ByZWd1bnRhX3JldGFhIEFTDQogICAgICAgICAgICAgICAgICAgICAgICAgIHAgTEVGVCBPVVRFUiBKT0lOICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYSBBUw0KICAgICAgICAgICAgICAgICAgICAgICAgICBjIE9OIHAuaWQgPSBjLmlkX3RpcG9fcHJlZ3VudGEgV0hFUkUgKHAuaWRfZmlsdHJvIElODQogICAgICAgICAgICAgICAgICAgICAgICAgIChjYy5pZF90aXBvX3ByZWd1bnRhKSkgQU5EIChjLmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBjLmlkX3RpcG9fcHJlZ3VudGEpKSBBTkQgKHQubml2ZWwgPSB4eC5pZF9uaXZlbCkgQU5EICh0Lm1heF9lc3RhZG8gPSAxKSBBTkQgKHQuaWRfY2FyYWN0ID0gY2MuaWRfY2FyYWN0XzIpIEFORCAodC5lc3RhZG9fbml2ZWwgPSAxKSBBTkQgKGMuaWRfem9uYSA9IHh4LmlkX3pvbmEpIEFORA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoZXN0YWRvID0gMSkgQU5EIChpZF90cmFucyA9IHQuaWRfdHJhbnMpKSA+IDApKSBBUyBhXzIpLCAwKSBBUyBERUNJTUFMKDEwLCAyKSkgQVMgQWx0b19Qcm9tZWRpb19tYXgsICdodHRwOi8vYmMtc2VsbG9zL1BydWViYVJldGFhL3BvcF91cF9YX3J1YnJvcy5hc3B4P3Bhcj0nICsgQ0FTVChAaWRfY2FtcGHDsWEgQVMgbnZhcmNoYXIoMSkpIA0KICAgICAgICAgICAgICAgICAgKyAnOycgKyBDQVNUKHh4LmlkX2dyYW5vIEFTIG52YXJjaGFyKDIpKSArICc7JyArIENBU1QoeHguaWRfem9uYSBBUyBudmFyY2hhcigyKSkgKyAnOycgKyBDQVNUKGNjLmlkX3RpcG9fcHJlZ3VudGEgQVMgbnZhcmNoYXIoMikpICsgJzsnICsgQ0FTVChjYy5pZF9jYXJhY3RfMiBBUyBudmFyY2hhcigzKSkgKyAnOycgKyBDQVNUKHh4LmlkX25pdmVsIEFTIG52YXJjaGFyKDMpKSArICc7JyArICcwJyBBUyBVUkwsIA0KICAgICAgICAgICAgICAgICAgQ0FTVChJU05VTEwNCiAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBTVU0obWluKSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgKFNFTEVDVCBJU05VTEwodC5taW4sIDApIEFTIG1pbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYV90cmFucyBBUyB0IExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgYyBPTiBjLmlkX3RyYW5zID0gdC5pZF90cmFucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHQubWluIElTIE5PVCBOVUxMKSBBTkQgKHQuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykgQU5EICh0LmlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSBBTkQgKHQuaWRfdGlwb19wcmVndW50YSBJTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGMuaWRfdGlwb19wcmVndW50YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIHRpcG9fcHJlZ3VudGFfcmV0YWEgQVMgcCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhIEFTIGMgT04gcC5pZCA9IGMuaWRfdGlwb19wcmVndW50YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAocC5pZF9maWx0cm8gPSBjYy5pZF90aXBvX3ByZWd1bnRhKSBBTkQgKGMuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdST1VQIEJZIGMuaWRfdGlwb19wcmVndW50YSkpIEFORCAodC5uaXZlbCA9IHh4LmlkX25pdmVsKSBBTkQgKHQubWluX2VzdGFkbyA9IDEpIEFORCAodC5pZF9jYXJhY3QgPSBjYy5pZF9jYXJhY3RfMikgQU5EICh0LmVzdGFkb19uaXZlbCA9IDEpIEFORCAoYy5pZF96b25hID0geHguaWRfem9uYSkgQU5EDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYV83DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoZXN0YWRvID0gMSkgQU5EIChpZF90cmFucyA9IHQuaWRfdHJhbnMpKSA+IDApKSBBUyBhXzJfMSksIDApIEFTIERFQ0lNQUwoMTAsIDIpKSBBUyBBbHRvX1Byb21lZGlvX21pbiwgSVNOVUxMDQogICAgICAgICAgICAgICAgICAgICAgKChTRUxFQ1QgU1VNKG1heF9udWxsKSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgKFNFTEVDVCAoQ0FTRSBXSEVOIHBvcmNfYXBsaWMgSVMgTlVMTCBUSEVOIElTTlVMTCh0IC5tYXgsIDApIEVMU0UgSVNOVUxMKHQgLm1heCwgMCkgKiBwb3JjX2FwbGljIC8gMTAwIEVORCkgQVMgbWF4X251bGwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGMgT04gYy5pZF90cmFucyA9IHQuaWRfdHJhbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgICh0LmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pIEFORCAodC5pZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkgQU5EICh0LmlkX3RpcG9fcHJlZ3VudGEgSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBjLmlkX3RpcG9fcHJlZ3VudGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICB0aXBvX3ByZWd1bnRhX3JldGFhIEFTIHAgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYSBBUyBjIE9OIHAuaWQgPSBjLmlkX3RpcG9fcHJlZ3VudGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHAuaWRfZmlsdHJvID0gY2MuaWRfdGlwb19wcmVndW50YSkgQU5EIChjLmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBjLmlkX3RpcG9fcHJlZ3VudGEpKSBBTkQgKHQubml2ZWwgPSB4eC5pZF9uaXZlbCkgQU5EICh0Lm1heF9lc3RhZG8gPSAxKSBBTkQgKHQuaWRfY2FyYWN0ID0gY2MuaWRfY2FyYWN0XzIpIEFORCAodC5lc3RhZG9fbml2ZWwgPSAxKSBBTkQgKGMuaWRfem9uYSA9IHh4LmlkX3pvbmEpIEFORA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWFfNg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGVzdGFkbyA9IDEpIEFORCAoaWRfdHJhbnMgPSB0LmlkX3RyYW5zKSkgPiAwKSkgQVMgZ2dfMSksIDApIEFTIEFsdG9fUHJvbWVkaW9fbWF4X251bGwsIElTTlVMTA0KICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIFNVTShtYXhfbnVsbCkgLyBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIChTRUxFQ1QgKENBU0UgV0hFTiBwb3JjX2FwbGljIElTIE5VTEwgVEhFTiBJU05VTEwodCAubWluLCAwKSBFTFNFIElTTlVMTCh0IC5taW4sIDApICogcG9yY19hcGxpYyAvIDEwMCBFTkQpIEFTIG1heF9udWxsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhX3RyYW5zIEFTIHQgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjIE9OIGMuaWRfdHJhbnMgPSB0LmlkX3RyYW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhIElODQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgYy5pZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgdGlwb19wcmVndW50YV9yZXRhYSBBUyBwIExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgQVMgYyBPTiBwLmlkID0gYy5pZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChwLmlkX2ZpbHRybyA9IGNjLmlkX3RpcG9fcHJlZ3VudGEpIEFORCAoYy5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgYy5pZF90aXBvX3ByZWd1bnRhKSkgQU5EICh0Lm5pdmVsID0geHguaWRfbml2ZWwpIEFORCAodC5taW5fZXN0YWRvID0gMSkgQU5EICh0LmlkX2NhcmFjdCA9IGNjLmlkX2NhcmFjdF8yKSBBTkQgKHQuZXN0YWRvX25pdmVsID0gMSkgQU5EIChjLmlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKChTRUxFQ1QgQ09VTlQoMSkgQVMgRXhwcjENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhXzUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChlc3RhZG8gPSAxKSBBTkQgKGlkX3RyYW5zID0gdC5pZF90cmFucykpID4gMCkpIEFTIGdnXzFfMSksIDApIEFTIEFsdG9fUHJvbWVkaW9fbWluX251bGwsIGNjLmlkX2luZGljZSwNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGRlc2NyaXBjaW9uDQogICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICB0aXBvX3ByZWd1bnRhX3JldGFhDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgaWRfZmlsdHJvDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIHRpcG9fcHJlZ3VudGFfcmV0YWEgQVMgdGlwb19wcmVndW50YV9yZXRhYV8zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWQgSU4gKGNjLmlkX3RpcG9fcHJlZ3VudGEpKSkpKSBBUyBkZXNfY29uc3VsdGEsIENBU1QNCiAgICAgICAgICAgICAgICAgICAgICAoKChTRUxFQ1QgU1VNKG1heCkgLyBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICAoU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYV90cmFucyBBUyB0IExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGMgT04gYy5pZF90cmFucyA9IHQuaWRfdHJhbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgVE9QICgxKSBpZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIGNhcmFjdF9pZF9ncmFubyBBUyBjYXJhY3RfaWRfZ3Jhbm9fMg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpKSkgQU5EICh0Lm5pdmVsID0gMSkgQU5EICh0LmlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpIEFORCAodC5tYXhfZXN0YWRvID0gMSkgQU5EIChjLmlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWFfMg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChlc3RhZG8gPSAxKSBBTkQgKGlkX3RyYW5zID0gdC5pZF90cmFucykpID4gMCkpIEFTIGFfMl8xXzIpICsNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIFNVTShtaW4pIC8gQ09VTlQoMSkgQVMgRXhwcjENCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIChTRUxFQ1QgSVNOVUxMKHQubWluLCAwKSBBUyBtaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYV90cmFucyBBUyB0IExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjIE9OIGMuaWRfdHJhbnMgPSB0LmlkX3RyYW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgICh0LmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pIEFORCAodC5pZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkgQU5EICh0LmlkX3RpcG9fcHJlZ3VudGEgPQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgVE9QICgxKSBpZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYXJhY3RfaWRfZ3Jhbm8gQVMgY2FyYWN0X2lkX2dyYW5vXzENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWRfY2FyYWN0ID0gZ2cuaWRfZmlsdHJvX2NhcmFjdCkpKSBBTkQgKHQubml2ZWwgPSAxKSBBTkQgKHQuaWRfY2FyYWN0ID0gZ2cuaWRfZmlsdHJvX2NhcmFjdCkgQU5EICh0Lm1pbl9lc3RhZG8gPSAxKSBBTkQgKGMuaWRfem9uYSA9IHh4LmlkX3pvbmEpIEFORA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhXzENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGVzdGFkbyA9IDEpIEFORCAoaWRfdHJhbnMgPSB0LmlkX3RyYW5zKSkgPiAwKSkgQVMgYV8yXzFfMV8xKSkgLyAyIC8gMTAwICoNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIHN1cGVyZmljaWUNCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFubyBBUyBTdXBlcmZpY2llX3JldGFhX3hfY2FtcGHDsWFfZ3Jhbm9fMQ0KICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9IGdnLmlkX2dyYW5vX3JlcG9ydCkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkpIEFTIERFQ0lNQUwoMTAsIDApKSBBUyBzdXBlcmZpY2llXzIsIENBU1QNCiAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBzdXBlcmZpY2llDQogICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vDQogICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9IGdnLmlkX2dyYW5vX3JlcG9ydCkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkpIEFTIERFQ0lNQUwoMTAsIDApKSBBUyBzdXBlcmZpY2llLCB6ei5pbmRpY2UsDQogICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBTVU0obWF4KSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICAoU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgYyBPTiBjLmlkX3RyYW5zID0gdC5pZF90cmFucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhID0gMikgQU5EICh0Lm5pdmVsID0geHguaWRfbml2ZWwpIEFORCAodC5pZF9jYXJhY3QgPSA0KSBBTkQgKHQubWF4X2VzdGFkbyA9IDEpIEFORCAoYy5pZF96b25hID0geHguaWRfem9uYSkgQU5EDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKChTRUxFQ1QgQ09VTlQoMSkgQVMgRXhwcjENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWFfNA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoZXN0YWRvID0gMSkgQU5EIChpZF90cmFucyA9IHQuaWRfdHJhbnMpKSA+IDApKSBBUyBhXzJfMV8xKSBBUyBBbHRvX1Byb21lZGlvX21heF9kaXN0cmlidWNpb24sDQogICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBTVU0obWF4KSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICAoU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgYyBPTiBjLmlkX3RyYW5zID0gdC5pZF90cmFucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyBJTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgSURfTUFQQQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19ncmFub19yZXBvcnRlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZCA9IGdnLmlkX2dyYW5vX3JlcG9ydCkpKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIFRPUCAoMSkgaWRfdGlwb19wcmVndW50YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgY2FyYWN0X2lkX2dyYW5vIEFTIGNhcmFjdF9pZF9ncmFub18yDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpKSkgQU5EICh0Lm5pdmVsID0gMSkgQU5EICh0LmlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpIEFORCAodC5tYXhfZXN0YWRvID0gMSkgQU5EIChjLmlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYV8yDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChlc3RhZG8gPSAxKSBBTkQgKGlkX3RyYW5zID0gdC5pZF90cmFucykpID4gMCkpIEFTIGFfMl8xXzJfMSkgKg0KICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1Qgc3VwZXJmaWNpZQ0KICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vIEFTIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFub18xDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2dyYW5vID0gZ2cuaWRfZ3Jhbm9fcmVwb3J0KSBBTkQgKGlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQgKGlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSkgLyAxMDAgQVMgc3VwZXJmaWNpZV8zLA0KICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgcHJpbWVyYQ0KICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vIEFTIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFub18yDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2dyYW5vID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgaWRfZ3Jhbm9fcmVwb3J0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFRpcG9fZ3Jhbm8gQVMgVGlwb19ncmFub18yDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWQgPSB4eC5pZF9ncmFubykpKSBBTkQgKGlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSBBTkQgKGlkX3pvbmEgPSB4eC5pZF96b25hKSkgKg0KICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1Qgc3VwZXJmaWNpZQ0KICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vIEFTIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFub18zDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2dyYW5vID0gZ2cuaWRfZ3Jhbm9fcmVwb3J0KSBBTkQgKGlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQgKGlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSkgLyAxMDAgQVMgUGFzX3ByaW1lcmFfc3VwZXJmaWNpZSwNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIHNlZ3VuZGENCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFubyBBUyBTdXBlcmZpY2llX3JldGFhX3hfY2FtcGHDsWFfZ3Jhbm9fMQ0KICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGlkX2dyYW5vX3JlcG9ydA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2dyYW5vIEFTIFRpcG9fZ3Jhbm9fMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkID0geHguaWRfZ3Jhbm8pKSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkpICoNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIHN1cGVyZmljaWUNCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFubyBBUyBTdXBlcmZpY2llX3JldGFhX3hfY2FtcGHDsWFfZ3Jhbm9fNA0KICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9IGdnLmlkX2dyYW5vX3JlcG9ydCkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkpIC8gMTAwIEFTIHBhc19zZWd1bmRhX3N1cGVyZmljaWUsIGNjLnRpcG9fdW5pZGFkLCBDQVNFIFdIRU4gY2MuaWRfdGlwb19wcmVndW50YSA9IDcgT1INCiAgICAgICAgICAgICAgICAgIGNjLmlkX3RpcG9fcHJlZ3VudGEgPSA2IFRIRU4NCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIFRPUCAoMSkgQ29lZmljaWVudGUNCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgaWRfY2FyYWN0ID0gY2MuaWRfY2FyYWN0KSBFTFNFICctMScgRU5EIEFTIGNvZWZpY2llbnRlLCBsLmRlc2NyaXBjaW9uIEFTIGNhbXBhw7FhDQpGUk9NICAgICBHcmFub3Nfem9uYXNfcmV0YWEgQVMgeHggTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX3pvbmFfcmV0YWEgQVMgenogT04geHguaWRfem9uYSA9IHp6LmlkX3pvbmEgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX25pdmVsIEFTIG5uIE9OIHh4LmlkX25pdmVsID0gbm4uaWRfbml2ZWwgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX2dyYW5vIEFTIGdnIE9OIHh4LmlkX2dyYW5vID0gZ2cuaWQgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYSBBUyBjYyBPTiB4eC5pZF9ncmFubyA9IGNjLmlkX2dyYW5vIEFORCBjYy5pZF90aXBvX3ByZWd1bnRhIElODQogICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBjLmlkX3RpcG9fcHJlZ3VudGENCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIHRpcG9fcHJlZ3VudGFfcmV0YWEgQVMgcCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgQVMgYyBPTiBwLmlkID0gYy5pZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHAuaWRfZmlsdHJvIElOIChAaWRfY29uc3VsdGEpKSBBTkQgKGMuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykNCiAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgYy5pZF90aXBvX3ByZWd1bnRhKSBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgIEHDsW9fY2FtcGHDsWFzIEFTIGwgT04gY2MuaWRfY2FtcGHDsWEgPSBsLmlkDQpXSEVSRSAgKHh4LmlkX2dyYW5vIElOIChAaWRfZ3Jhbm8pKSBBTkQgKHh4LmlkX3pvbmEgSU4gKEBpZF96b25hKSkgQU5EICh4eC5pZF9uaXZlbCBJTiAoQGlkX25pdmVsKSkgQU5EIChjYy5pZF9jYXJhY3RfMiA8PiAxMDQpIEFORCAoY2MuaWRfY2FyYWN0XzIgPD4gMTA1KSBBTkQgKGNjLmlkX2NhcmFjdF8yIDw+IDEwNikgQU5EIChjYy5pZF9jYXJhY3RfMiA8PiAxMDcpIEFORCAoY2MuaWRfY2FyYWN0XzIgPD4gMTA4KSBBTkQgDQogICAgICAgICAgICAgICAgICAoY2MuaWRfY2FyYWN0XzIgPD4gNjUpIEFORCAoY2MuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpOyIpDQoNCg0KY29uc3VsdGFfUnViZW4NCmBgYA0KDQojIyMgUGFxdWV0ZSBgREJJYA0KDQpEQkkgcGVybWl0ZSBjb25lY3Rhcm5vIGEgbGEgYmFzZSBkZSBkYXRvcyBkZSBTUUwuIFBhcmEgaGFjZXJsbyBkZWJlbW9zIGNvbmZpZ3VyYXIgbG9zIGNhbXBvcy4gTGEgY29uZXhpw7NuIHNlIHB1ZWRlIHZlcmlmaWNhciBlbiBlbCBwYW5lbCBzdXBlcmlvciBkZXJlY2hvLg0KDQpMYSBiYXNlIGRhdG9zIGRlbCBSZVRBQSBlc3RhIGNvbXB1ZXN0YSBwb3IgNiB0YWJsYXMgcHJpbmNpcGFsZXMgIkHDsW8gQ2FtcGHDsWFzIiwgImNhYmVjZXJhX3RybnNhY2Npb25lc19yZXRhYSIsICAiY2FyYWN0X2lkX2dyYW5vIiwgImNhcmFjdF9pZF9ncmFub19jYW1wYcODwrFhX3Zpc3RhIiwgIkNvbGFib3JhZG9yZXMiICB5ICJHcmFub3Nfem9uYXNfcmV0YWEiLg0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KI01lIGNvbmVjdG8gYSBsYSBiYXNlDQpjb24gPC0gREJJOjpkYkNvbm5lY3Qob2RiYzo6b2RiYygpLA0KICAgICAgICAgICAgICAgICAgICAgIERyaXZlciAgICA9ICJTUUwgU2VydmVyIiwgDQogICAgICAgICAgICAgICAgICAgICAgU2VydmVyICAgID0gIkJDLVJFVEEiLA0KICAgICAgICAgICAgICAgICAgICAgIERhdGFiYXNlICA9ICJFc3RpbWFjaW9uZXNfY29waWEiLA0KICAgICAgICAgICAgICAgICAgICAgIFVJRCAgICAgICA9ICJlc3RpbWFjaW9uZXNfY29uc3VsdGEiLA0KICAgICAgICAgICAgICAgICAgICAgIFBXRCAgICAgICA9ICJFc3RpLmJjLjIwMTkyMyIsDQogICAgICAgICAgICAgICAgICAgICAgUG9ydCAgICAgID0gMTQzMywNCiAgICAgICAgICAgICAgICAgICAgICBkYm5hbWUgPSAiRXN0aW1hY2lvbmVzX0NvcGlhIiwNCiAgICAgICAgICAgICAgICAgICAgICBlbmNvZGluZyA9ICJsYXRpbjEiKQ0KDQpEQkk6OmRiTGlzdFRhYmxlcyhjb24pWzE6Nl0jbGlzdGEgZGUgbGFzIHRhYmxhcyBkZSBsYSBiYXNlDQpgYGANCiANCmxhIGZ1bmNpw7NuIGB0YmxgIGRlIGBkcGx5cmAgdHJhZSBsYXMgdGFibGFzIGRlIGxhIGJhc2UgZGUgZGF0b3MuIFRhbWJpZW4gcG9kZW1vcyBhcGxpY2FyIGEgZXN0YSB0YWJsYSB0b2RhcyBsYXMgZnVuY2lvbmVzIHF1ZSB2aW1vcyBlbiBsYXMgY2xhc2VzIHByZXZpYXMuDQoNClZlYW1vcyBhbGd1bmFzIGRlIGxhcyB0YWJsYXMgcXVlIGNvbmZvcm1hbiBsYSBiYXNlIGRlbCBSZVRBQS4NCg0KDQojIyMjIFRhYmxhIFRpcG9fZ3Jhbm8NCmBgYHtyLCBlY2hvPVRSVUV9DQojVGFibGEgaWQgZ3Jhbm8NClRpcG9fZ3Jhbm8gPC0gIHRibChjb24sIGMoIlRpcG9fZ3Jhbm8iKSkgJT4lIA0KICBzZWxlY3QoaWQsZGVzY3JpcGNpb24pICU+JSByZW5hbWUoaWRfZ3Jhbm8gPSBpZCwgZGVzY3JpcGNpb25fZ3Jhbm8gPSBkZXNjcmlwY2lvbikgJT4lIGZpbHRlcihpZF9ncmFubz4wKQ0KVGlwb19ncmFubyANCmBgYA0KDQojIyMjIFRhYmxhIEHDsW9fY2FtcGHDsWFzDQpgYGB7ciwgZWNobz1UUlVFfQ0KI3NlbGVjY2lvbm8gdGFibGEgaWQgY2FtcGHDsWENCkFuaW9fY2FtcGFuaWFzIDwtICB0YmwoY29uLCBjKCJBw7FvX2NhbXBhw7FhcyIpKSAlPiUgcmVuYW1lKGlkX2NhbXBhbmlhID0gaWQsIGRlc2NyaXBjaW9uX2NhbXBhbmlhID0gZGVzY3JpcGNpb24pICU+JSBmaWx0ZXIoaWRfY2FtcGFuaWE+MCkNCg0KQW5pb19jYW1wYW5pYXMgDQpgYGANCg0KIyMjIyBUYWJsYSBUaXBvX3pvbmFfcmV0YWENCmBgYHtyLCBlY2hvPVRSVUV9DQojY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYQ0KVGlwb196b25hX3JldGFhIDwtIHRibChjb24sIGMoIlRpcG9fem9uYV9yZXRhYSIpKSAlPiUgc2VsZWN0KGlkX3pvbmEsZGVzY3JpcGNpb24sZGVzY3JpcGNpb24yKSAlPiUgcmVuYW1lKGRlc2NyaXBjaW9uX3pvbmFfcmV0YWEgPSBkZXNjcmlwY2lvbiwNCiAgICAgICBkZXNjcmlwY2lvbl96b25hX3JldGFhMiA9IGRlc2NyaXBjaW9uMikNClRpcG9fem9uYV9yZXRhYSAgJT4lIGhlYWQoMTApDQpgYGANCg0KDQoNCiMjIyMgVGFibGEgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYQ0KYGBge3IsIGVjaG89VFJVRX0NCiNjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhDQpjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIDwtIHRibChjb24sIGMoImNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEiKSkgJT4lIHNlbGVjdChpZF90cmFucyxpZF9jb2xhYm9yYWRvcixlc3RhZG8pDQpjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhICAlPiUgaGVhZCgxMCkNCmBgYA0KDQojIyMjIFRhYmxhIHRpcG9fcHJlZ3VudGFfcmV0YWENCmBgYHtyLCBlY2hvPVRSVUV9DQojY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYQ0KdGlwb19wcmVndW50YV9yZXRhYSA8LSB0YmwoY29uLCBjKCJ0aXBvX3ByZWd1bnRhX3JldGFhIikpICU+JSANCiAgc2VsZWN0KGlkLGRlc2NyaXBjaW9uKSAlPiUgcmVuYW1lKGlkX3ByZWd1bnRhID0gaWQsIGRlc2NyaXBjaW9uX3ByZWd1bnRhID0gZGVzY3JpcGNpb24pICU+JSBhc190aWJibGUoKQ0KdGlwb19wcmVndW50YV9yZXRhYQ0KYGBgDQoNCiMjIyMgVGFibGEgdGlwb19jYXJhY3RlcmlzdGljYV9yZXRhYQ0KYGBge3IsIGVjaG89VFJVRX0NCiNjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhDQpUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYSA8LSB0YmwoY29uLCBjKCJUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYV90cmFucyIpKQ0KVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWENCmBgYA0KDQoNCiMjIyMgVGFibGEgQ29sYWJvcmFkb3Jlcw0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KI1RhYmxhIENvbGFib3JhZG9yZXMNCkNvbGFib3JhZG9yZXMgPC0gdGJsKGNvbiwgYygiQ29sYWJvcmFkb3JlcyIpKQ0KQ29sYWJvcmFkb3JlcyAlPiUgdmFyaWFibGUubmFtZXMoKQ0KYGBgDQoNClRhbWJpZW4gcG9kZW1vcyB2aXN1YWxpemFyIGxhcyBjb25leHhpb25lcyBlbnRyZSBsYXMgdGFibGFzIGNvbiBlbCBwYXF1ZXRlIGBkYXRhbW9kZWxyYCBxdWUgbm9zIHBlcm1pdGUgY29uc3RydWlyIGRpYWdyYW1hcyBlbnRpZGFkLXJlYWxhY2nDs24NCg0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTl9DQpsaWJyYXJ5KGRhdGFtb2RlbHIpICNwYXF1ZXRlIHBhcmEgYXJtYXIgZGlhZ3JhbWEgZGUgZW50aWRhZCByZWxhY2lvbg0KDQpjb25lY2Npb24gPC0gb2RiY0RyaXZlckNvbm5lY3QoDQogIGNvbm5lY3Rpb24gPSAiRHJpdmVyPVNRTCBTZXJ2ZXI7IFNlcnZlcj1CQy1SRVRBOyBEYXRhYmFzZT1Fc3RpbWFjaW9uZXNfY29waWE7IFVJRD1lc3RpbWFjaW9uZXNfY29uc3VsdGE7IFB3ZD1Fc3RpLmJjLjIwMTkyMyINCiAgKQ0KDQpzUXVlcnkgPC0gZG1fcmVfcXVlcnkoInNxbHNlcnZlciIpDQpkbV9yZXRhYSA8LSBzcWxRdWVyeShjaGFubmVsID0gY29uZWNjaW9uLCBzUXVlcnksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwgZXJyb3JzPVRSVUUpDQpkbV9yZXRhYSA8LSBhcy5kYXRhX21vZGVsKGRtX3JldGFhKSAjcGFzbyBhIGZvcm1hdG8gbW9kZWxvDQoNCmZvY3VzIDwtbGlzdCh0YWJsZXMgID0gYygiQcOxb19jYW1wYcOxYXMiLCJjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIiwiY2FyYWN0X2lkX2dyYW5vIiwgICAgICAgICAgICAgICANCiJjYXJhY3RfaWRfZ3Jhbm9fY2FtcGHDsWFfdmlzdGEiLCJDb2xhYm9yYWRvcmVzIiwiR3Jhbm9zX3pvbmFzX3JldGFhIikpIA0KIA0KZ3JhcGggPC0gZG1fY3JlYXRlX2dyYXBoKGRtX3JldGFhICwgcmFua2RpciA9ICJCVCIsIGZvY3VzID0gZm9jdXMsIGNvbF9hdHRyID0gYygiY29sdW1uIiwgInR5cGUiKSkgDQpkbV9yZW5kZXJfZ3JhcGgoZ3JhcGgpICNncmFmaWNvDQpgYGANCg0KDQojIyMgUXVlcnkgU1FMIHZzIGRwbHlyDQoNCkVuIGVzdGEgc2VjY2lvbiB2YW1vcyBhIHJlcGxpY2FyIGxhIGNvbnN1bHRhIFNRTCBxdWUgdmltb3MgYXJyaWJhIHBlcm8gZW4gZm9tcmF0byBkcGx5ci4gVmFtb3MgYSB2ZXIgcXVlIHVuYSBjb25zdWx0YSBtdXkgZXh0ZW5zYSBzZSBwdWVkZSByZWFsaXphciBlbiB1bmEgZm9tcmEgbcOhcyBwcm9saWphIHkgYnJldmUuDQoNCkVsIGNvbWFuZG9gc2hvd19xdWVyeWAgcGVybWl0ZSBleHRyYWVyIGxhIGNvbnN1bHRhIGVuIGZvcm1hdG8gU1FMLg0KDQpgYGB7ciBlY2hvPVRSVUV9DQp0YWJsYV9jb25zdWx0YV9zcWwgPC0gVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgJT4lICANCiAgbGVmdF9qb2luKGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEsYnkgPSBjKCJpZF90cmFucyIsImlkX2NvbGFib3JhZG9yIikpICU+JSAjam9pbiBjb24gdGFibGEgY2FiZWNlcmENCiAgbGVmdF9qb2luKFRpcG9fZ3Jhbm8gLGJ5ID0gImlkX2dyYW5vIikgJT4lDQogIGxlZnRfam9pbihBbmlvX2NhbXBhbmlhcyAsYnkgPSBjKCJpZF9jYW1wYcOxYSI9ImlkX2NhbXBhbmlhIikgKSAlPiUNCiAgbGVmdF9qb2luKFRpcG9fem9uYV9yZXRhYSwgYnkgPSBjKCJpZF96b25hIikgICkgJT4lIA0KICBmaWx0ZXIoaWRfY2FtcGHDsWEgPT0gOSxpZF96b25hPT01LG5pdmVsPT0xLGlkX2dyYW5vPT0xLA0KICAgICAgICAgaWRfdGlwb19wcmVndW50YT09NiwgbWF4X2VzdGFkbyA9PSAxLCBlc3RhZG89PTEpICU+JQ0KICBncm91cF9ieShkZXNjcmlwY2lvbl9ncmFubywgaWRfZ3Jhbm8sIGRlc2NyaXBjaW9uX2NhbXBhbmlhLCBpZF9jYW1wYcOxYSwgZGVzY3JpcGNpb25fem9uYV9yZXRhYSwgaWRfem9uYSwNCiAgICAgICAgICBuaXZlbCwgaWRfdGlwb19wcmVndW50YSwgaWRfY2FyYWN0LGRlc2NyaXBjaW9uKSAlPiUgDQogIHN1bW1hcmlzZShwcm9tZWRpb19tYXggPSByb3VuZChtZWFuKG1heCwgbmEucm0gPSBUKSwyKSwNCiAgICAgICAgICAgIHByb21lZGlvX21pbiA9IHJvdW5kKG1lYW4obWluLCBuYS5ybSA9IFQpLDIpKSANCg0KdGFibGFfY29uc3VsdGFfc3FsICU+JSBkcGx5cjo6c2hvd19xdWVyeSgpICN2ZXIgcXVlcnkgU1FMDQoNCnRhYmxhX2NvbnN1bHRhX3NxbCAjc2FsaWRhDQpgYGANCg0KIyMjIFBsYW50ZW9zIFRlY25vbG9naWNvcw0KDQpDb25zdHJ1aXIgbG9zIHBsYW50ZW9zIHRlY25vbMOzZ2ljb3Mgc3VlbGUgc2VyIHVuIHRyYWJham8gcXVlIHRlZGlvc28gcXVlIG5vIGVzdGEgYXV0b21hdGl6YWRvIHkgc3VlbGUgdG9tYXIgYmFzdGFudGUgdGllbXBvLiBFbiBlc3RhIHNlY2Npw7NuIGJ1c2NhbW9zIGF1dG9tYXRpemFyIGxhIGNvbnN0cnVjY2nDs24gZGUgbG9zIHBsYW50ZW9zLg0KDQoNCmBgYHtyIGVjaG89VFJVRX0NCiMgdGFibGEgY29uIHRvZGFzIGxvcyBpbnN1bW9zIGluY2x1aWRvcyBlbiBsYSBiYXNlDQp0YWJsYV92YXJpYWJsZXMgPC0gVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgJT4lIGRpc3RpbmN0KGRlc2NyaXBjaW9uLHRpcG9fdW5pZGFkKSAlPiUgYXNfdGliYmxlKCkNCg0KI2xpc3RhIGRlIHZhcmlhYmxlcyBpbmNsdWlkYXMNCnZhcmlhYmxlc19wbGFudGVvIDwtIGMoIkFkb3BjacOzbiBkZSBOVCIsIm1heF9taW4iLCJuaXZlbCIsImlkX2NhbXBhw7FhIiwiaWRfZ3Jhbm8iLCJpZF96b25hIiwNCiAgICAgICAgICAgICAgICAgICAgICAgImRlc2NyX2dyYW5vIiwiZGVzY3JfY2FtcGFuaWEiLCJTZW1pbGxhIiwiVXJlYSIsIlBEQSIsDQogICAgICAgICAgICAgICAgICAgICAgICJHbGlmb3NhdG8gY29uY2VudHJhZG8gLSBCYXJiZWNobyIsDQogICAgICAgICAgICAgICAgICAgICAgICJHbGlmb3NhdG8gY29uY2VudHJhZG8gLSBjdWx0aXZvIiwiSGliLiBSUiBCdDIiLCIyLTREIiwiRGljYW1iYSIsDQogICAgICAgICAgICAgICAgICAgICAgICJNZXRzdWxmdXLDs24iLA0KICAgICAgICAgICAgICAgICAgICAgICAiU1BTIiwiQXRyYXppbmEiLCJNZXRvbGFjbG9yIiwiUGljbG9yw6FtIiwiRGlhbWlkYXMiLCJEaWNsb3N1bGFtIiwgDQogICAgICAgICAgICAgICAgICAgICAgICJGdW5naWNpZGEgMSAoRXN0cm9iLiArIFRyaWF6b2wpIiwiU2VtaWxsYSIsICJJbm9jLiArIEZ1bmdpYy4iLA0KICAgICAgICAgICAgICAgICAgICAgICAiSW5vY3VsYW50ZSAxIChmdWxsKSIsIkZvc2ZvcmFkb3MgMSIsICJGb3Nmb3JhZG9zIDIiLA0KICAgICAgICAgICAgICAgICAgICAgICAiQ3VyYXNlbWlsbGEgLSBGdW5naWNpZGEgYmFzZSIsIkNsb3JpbXVyw7NuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIlBNQSIsIkRpbWV0b2F0byIsICJDdXJhc2VtaWxsYSAyIC0gRnVuZ2ljaWRhIiwNCiJDdXJhc2VtaWxsYSAyIC0gZnVuZ2ljLiIsIgkNCkZ1bmdpY2lkYSAyIikNCmBgYA0KDQoNCg0KYGBge3J9DQojQXJtbyBsYSBjb25zdWx0YSBkZSBwbGFudGVvcw0KcGxhbnRlb3MgPC0gVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgJT4lICANCiAgZmlsdGVyKGRlc2NyaXBjaW9uICVpbiUgdmFyaWFibGVzX3BsYW50ZW8pICU+JSAjbWUgcXVlZG8gY29uIGluc3Vtb3MgaW5jbHVpZG9zIGVuIGxvcyBwbGFudGVvcw0KICBsZWZ0X2pvaW4oY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSwgYnkgPSBjKCJpZF90cmFucyIsImlkX2NvbGFib3JhZG9yIikpICU+JSANCiAgbGVmdF9qb2luKFRpcG9fem9uYV9yZXRhYSwgYnk9YygiaWRfem9uYSIpKSAlPiUgDQogIGxlZnRfam9pbihUaXBvX2dyYW5vLCBieT0iaWRfZ3Jhbm8iKSAlPiUNCiAgI2xlZnRfam9pbih0aXBvX3ByZWd1bnRhX3JldGFhLCBieSA9IGMoImlkX3RpcG9fcHJlZ3VudGEiPSAiaWRfcHJlZ3VudGEiKSkgJT4lIA0KICBsZWZ0X2pvaW4oQW5pb19jYW1wYW5pYXMsYnk9YygiaWRfY2FtcGHDsWEiPSJpZF9jYW1wYW5pYSIgKSkgJT4lDQogIGZpbHRlcihlc3RhZG89PTEpICU+JSAjZW5jdWVzdGFzIHZhbGlkYWRhcw0KICAjY29ycmVjaW9uIG1haXogdGFyZGlvIHBvciBjYXJnYSByZXRhYQ0KICBtdXRhdGUoaWRfZ3Jhbm8gPSBjYXNlX3doZW4oIChpZF9ncmFubz09OCAmIGlkX3pvbmEgJWluJSBjKDEsMiwxNikgKX4gNywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVCB+IGFzLmRvdWJsZShpZF9ncmFubykgKSwNCiAgICAgICAgIGRlc2NyaXBjaW9uX2dyYW5vID0gaWZlbHNlKGlkX2dyYW5vPT03LCAiTWHDrXogMcKwIFRlbXByYW5vIixkZXNjcmlwY2lvbl9ncmFubykNCiAgICAgICAgICkgJT4lIA0KICBtdXRhdGUobWF4ID0gY2FzZV93aGVuKHRpcG9fdW5pZGFkID09IiUiICYgaXMubmEobWF4KSB+IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgVCB+IGFzLm51bWVyaWMobWF4KSApLA0KICAgICAgICAgbWluID0gY2FzZV93aGVuKHRpcG9fdW5pZGFkID09IiUiICYgaXMubmEobWluKSB+IGFzLm51bWVyaWMobWF4KSwNCiAgICAgICAgIFQgfiBhcy5udW1lcmljKG1pbikNCiAgICAgICAgICAgICAgICAgICAgICAgICApDQogICAgICAgICApICU+JSANCiAgIGdyb3VwX2J5KCBpZF9jYW1wYcOxYSAsZGVzY3JpcGNpb25fY2FtcGFuaWEgLCBuaXZlbCwgDQogICAgICAgICAgICAgaWRfem9uYSwgZGVzY3JpcGNpb25fem9uYV9yZXRhYSwNCiAgICAgICAgICAgICBpZF9ncmFubywgZGVzY3JpcGNpb25fZ3Jhbm8sIGRlc2NyaXBjaW9uKSAlPiUgDQogIHN1bW1hcmlzZShwcm9tZWRpb19tYXggPSBtZWFuKG1heCwgbmEucm0gPSBUKSwgI3Byb21lZGlvIG1heGltbyBhcGxpY2Fkbw0KICAgICAgICAgICAgcHJvbWVkaW9fbWluID0gbWVhbihtaW4sIG5hLnJtID0gVCkgI3Byb21lZGlvIG1pbmltbyBhcGxpY2Fkbw0KICAgICAgICAgICAgI3Byb21lZGlvX3BvcmNfYXBsaWMgPSBtZWFuKHBvcmNfYXBsaWMsIG5hLnJtID0gVCkNCiAgICAgICAgICAgICkgJT4lIA0KICBtdXRhdGUoZG9ibGVfbmEgPSBpZmVsc2UoIGlzLm5hKHByb21lZGlvX21heCkgJiBpcy5uYShwcm9tZWRpb19taW4pLDEsMCApKSAlPiUNCiAgZmlsdGVyKGRvYmxlX25hICE9MSkgJT4lIA0KICBtdXRhdGUoIHByb21lZGlvID0gKHByb21lZGlvX21heCsgcHJvbWVkaW9fbWluKS8yKSAlPiUgDQogIHNlbGVjdCgtYyhwcm9tZWRpb19tYXgscHJvbWVkaW9fbWluKSApIA0KICANCg0KDQojRnVuY2lvbiBwYXJhIGVzY2FsYXIgZWwgbml2ZWwgZGUgYWRvcGNpb24gdGVjbm9sb2dpY2ENCiNlc2NhbGFyIDwtIGZ1bmN0aW9uKHgpeyB4ID0geC9zdW0oeCxuYS5ybSA9IFQpICoxMDAgfQ0KDQojR2VuZXJvIGRlc2NyaXBjaW9uIE5pdmVsIFRlY25vbMOzZ2ljbyB5IGVzY2FsbyBBZG9wY2lvbiBkZSBOVA0KcGxhbnRlb3MgPC0gcGxhbnRlb3MgJT4lIGFzX3RpYmJsZSgpICU+JSANCiAgbXV0YXRlKGRlc2NyaXBjaW9uX25pdmVsID0gY2FzZV93aGVuKG5pdmVsID09IDEgfiAiQWx0byIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuaXZlbCA9PSAyIH4gIk1lZGlvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5pdmVsID09IDMgfiAiQmFqbyIpKSAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBkZXNjcmlwY2lvbix2YWx1ZXNfZnJvbSA9IGMocHJvbWVkaW8pICkgJT4lIA0KICBncm91cF9ieShpZF9jYW1wYcOxYSxpZF96b25hLGlkX2dyYW5vKSMgJT4lDQogICNtdXRhdGUoQWRvcGNpb25fTlQgPSBlc2NhbGFyKGBBZG9wY2nDs24gZGUgTlRgKSkgICAjZXNjYWxvIGEgMTAwIGVsIG5pdmVsIHRlY25vbG9naWNvDQoNCiNQYXNvIGEgZm9ybWF0byBsb25nDQpwbGFudGVvcyA8LSBwbGFudGVvcyAlPiUNCiAgbXV0YXRlKGFkb3BjaW9uX250ID0gYEFkb3BjacOzbiBkZSBOVGApICU+JSANCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtYygiaWRfY2FtcGHDsWEiLCAiZGVzY3JpcGNpb25fY2FtcGFuaWEiLCJuaXZlbCIsImlkX3pvbmEiLCJkZXNjcmlwY2lvbl96b25hX3JldGFhIiAsImlkX2dyYW5vIiwiZGVzY3JpcGNpb25fZ3Jhbm8iLCAiZGVzY3JpcGNpb25fbml2ZWwiLCJhZG9wY2lvbl9udCIpICxuYW1lc190byA9ICJ2YXJpYWJsZXMiLHZhbHVlc190byA9ICJ2YWxvcmVzIikNCg0KVGlwb196b25hX3JldGFhDQpgYGANCg0KDQpgYGB7ciBlY2hvPVRSVUV9DQpwbGFudGVvc19wb25kIDwtIHBsYW50ZW9zICU+JQ0KICBncm91cF9ieShpZF9jYW1wYcOxYSxkZXNjcmlwY2lvbl9jYW1wYW5pYSxpZF96b25hLCBkZXNjcmlwY2lvbl96b25hX3JldGFhLA0KICAgICAgICAgICBpZF9ncmFubyxkZXNjcmlwY2lvbl9ncmFubyx2YXJpYWJsZXMpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKHZhbG9yZXMpICkgJT4lICNlc3RvIGVzIHBhcmEgbm8gY29udGFyIGxvcyBubyBjb250ZXN0YWRvcyB5IGNhbGN1bGFyIGxvcyBwbGFudGVvcyBSZXRhYSAicHJvbWVkaW8gc2ltcGxlIg0KICBzdW1tYXJpc2UodmFsb3JlcyA9ICB3ZWlnaHRlZC5tZWFuKHZhbG9yZXMgLHcgPSBhZG9wY2lvbl9udC8xMDAsbmEucm0gPSBUKQ0KICAgICAgICAgICAgKQ0KYGBgDQoNCiMjIyMgUGxhbnRlb3Mgey50YWJzZXR9DQoNCiMjIyMjIFNvamENCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9OX0NCnZhcmlhYmxlc19wbGFudGVvX3NvamEgPC1jKCJTZW1pbGxhIiwgIlNQUyIsIkdsaWZvc2F0byBjb25jZW50cmFkbyAtIEJhcmJlY2hvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJHbGlmb3NhdG8gY29uY2VudHJhZG8gLSBjdWx0aXZvIiwgIjItNEQiLCJDbG9yaW11csOzbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiTWV0c3VsZnVyw7NuIiwiRGljbG9zdWxhbSIsIkRpYW1pZGFzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJFc3Ryb2JpcnVsaW5hICsgVHJpYXpvbCIsIklub2N1bGFudGUgMSAoZnVsbCkiLCJJbm9jLiArIEZ1bmdpYy4iLCJGdW5naWNpZGEgMiIpIA0KDQoNCnBsYW50ZW9fc29qYSA8LSBwbGFudGVvc19wb25kICAlPiUgDQogIGZpbHRlcihkZXNjcmlwY2lvbl9ncmFubz09IlNvamEgMcKwIix2YXJpYWJsZXMgJWluJSB2YXJpYWJsZXNfcGxhbnRlb19zb2phKSAlPiUgdW5ncm91cCgpDQogIA0KICANCnBsYW50ZW9zX3BvbmQgICU+JSANCiAgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iU29qYSAxwrAiLHZhcmlhYmxlcyAlaW4lIHZhcmlhYmxlc19wbGFudGVvX3NvamEpICU+JSANCiAgZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh5PXZhbG9yZXMseD1kZXNjcmlwY2lvbl9jYW1wYW5pYSwgY29sb3I9YXMuZmFjdG9yKGRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpKSkrIA0KICBnZW9tX3BvaW50KCkgKyAgZmFjZXRfd3JhcCh+dmFyaWFibGVzLCBzY2FsZXMgPSAiZnJlZV95IikrDQogIGxhYnModGl0bGUgPSAgIkRvc2lzIGFwbGljYWRhcyAtIFNvamEgMcK6IikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBjb2xvcj0iWm9uYSIpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSINCiAgICAgICAgKSANCg0KYGBgDQoNCmBgYHtyfQ0KcGxhbnRlb3MgICU+JSANCiAgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iU29qYSAxwrAiLHZhcmlhYmxlcyAlaW4lIHZhcmlhYmxlc19wbGFudGVvX3NvamEpICU+JSANCiAgZmlsdGVyKGRlc2NyaXBjaW9uX2NhbXBhbmlhPT0iMjAxNy8yMDE4IixkZXNjcmlwY2lvbl96b25hX3JldGFhPT0iSUlJIikNCmBgYA0KDQpgYGB7cn0NCnBsYW50ZW9zICU+JSBmaWx0ZXIodmFyaWFibGVzPT0iQWRvcGNpw7NuIGRlIE5UIikgJT4lIGdyb3VwX2J5KGlkX2dyYW5vLCBkZXNjcmlwY2lvbl9ncmFubywgZGVzY3JpcGNpb25fem9uYV9yZXRhYSxkZXNjcmlwY2lvbl9jYW1wYW5pYSkgJT4lICBzdW1tYXJpc2UoYWRvcGNpb24gPSBzdW0odmFsb3JlcykpDQoNCnBsYW50ZW9zICU+JSBmaWx0ZXIoZGVzY3JpcGNpb25fY2FtcGFuaWE9PSIyMDE2LzIwMTciLCBkZXNjcmlwY2lvbl96b25hX3JldGFhPT0iSUlJIiwNCiAgICAgICAgICAgICAgICAgICAgaWRfZ3Jhbm89PTIsIHZhcmlhYmxlcz09IkFkb3BjacOzbiBkZSBOVCIpDQpgYGANCg0KIyMjIyMgVHJpZ28NCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9OX0NCnZhcmlhYmxlc19wbGFudGVvX1RyaWdvIDwtYygiU2VtaWxsYSIsIlVyZWEiLCJQTUEiLCJHbGlmb3NhdG8gY29uY2VudHJhZG8gLSBCYXJiZWNobyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiMi00RCIsIkRpY2FtYmEiLCAiTWV0c3VsZnVyw7NuIiwiRm9zZm9yYWRvcyAxIiwiRnVuZ2ljaWRhIDEgKEVzdHJvYi4gKyBUcmlhem9sKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiQ3VyYXNlbWlsbGEgMiAtIEZ1bmdpY2lkYSIsIkN1cmFzZW1pbGxhIDIgLSBmdW5naWMuIikgI0xhbWJkYWNpYWxvdHJpbmEgbm8gbG8gZW5jb250csOpDQoNCnBsYW50ZW9fdHJpZ28gPC0gcGxhbnRlb3NfcG9uZCAgJT4lIA0KICBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJUcmlnbyIsdmFyaWFibGVzICVpbiUgdmFyaWFibGVzX3BsYW50ZW9fVHJpZ28pICU+JSB1bmdyb3VwKCkNCiAgDQoNCnBsYW50ZW9zX3BvbmQgICU+JSANCiAgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iVHJpZ28iLHZhcmlhYmxlcyAlaW4lIHZhcmlhYmxlc19wbGFudGVvX1RyaWdvKSAlPiUgDQogIGdncGxvdCguLG1hcHBpbmcgPSBhZXMoeT12YWxvcmVzLHg9ZGVzY3JpcGNpb25fY2FtcGFuaWEsIGNvbG9yPWFzLmZhY3RvcihkZXNjcmlwY2lvbl96b25hX3JldGFhKSkpKyANCiAgZ2VvbV9wb2ludCgpICsgIGZhY2V0X3dyYXAofnZhcmlhYmxlcywgc2NhbGVzID0gImZyZWVfeSIpKw0KICBsYWJzKHRpdGxlID0gICJEb3NpcyBhcGxpY2FkYXMgLSBUcmlnbyIpKw0KICBsYWJzKHg9IkNhbXBhw7FhIiwgY29sb3I9IlpvbmEiKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iDQogICAgICAgICkgDQpgYGANCg0KIyMjIyMgTWFpeg0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCnZhcmlhYmxlc19wbGFudGVvX01haXogPC1jKCAiSGliLiBSUiBCdDIiLCAiVXJlYSIsIlBEQSIsIkdsaWZvc2F0byBjb25jZW50cmFkbyAtIEJhcmJlY2hvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJHbGlmb3NhdG8gY29uY2VudHJhZG8gLSBjdWx0aXZvIiwgIjItNEQiLCJBdHJhemluYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiTWV0b2xhY2xvciIsIlBpY2xvcsOhbSIsIkRpYW1pZGFzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJEaWNhbWJhIiwgIkVzdHJvYmlydWxpbmEgKyBUcmlhem9sIikgI0xhbWJkYWNpYWxvdHJpbmEgbm8gbG8gZW5jb250csOpDQoNCnBsYW50ZW9fbWFpeiA8LSBwbGFudGVvc19wb25kICAlPiUgDQogIGZpbHRlcihkZXNjcmlwY2lvbl9ncmFubz09Ik1hw616IDHCsCBUZW1wcmFubyIsdmFyaWFibGVzICVpbiUgdmFyaWFibGVzX3BsYW50ZW9fTWFpeikgJT4lIHVuZ3JvdXAoKSANCg0KcGxhbnRlb3NfcG9uZCAgJT4lIA0KICBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJNYcOteiAxwrAgVGVtcHJhbm8iLHZhcmlhYmxlcyAlaW4lIHZhcmlhYmxlc19wbGFudGVvX01haXopICU+JSANCiAgZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh5PXZhbG9yZXMseD1kZXNjcmlwY2lvbl9jYW1wYW5pYSwgY29sb3I9YXMuZmFjdG9yKGRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpKSkrIA0KICBnZW9tX3BvaW50KCkgKyAgZmFjZXRfd3JhcCh+dmFyaWFibGVzLCBzY2FsZXMgPSAiZnJlZV95IikrDQogIGxhYnModGl0bGUgPSAgIkRvc2lzIGFwbGljYWRhcyAtIE1haXoiKSsNCiAgbGFicyh4PSJDYW1wYcOxYSIsIGNvbG9yPSJab25hIikrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIg0KICAgICAgICApIA0KDQpgYGANCg0KIyMjIyB7LX0NCg0KR3VhcmRvIHBsYW50ZW9zDQpgYGB7cn0NCmxpYnJhcnkob3Blbnhsc3gpICNhY3RpdmFtb3MgbGEgbGlicmVyw61hDQoNCndyaXRlLnhsc3goeCA9IHBsYW50ZW9zX3BvbmQsIGZpbGUgPSAiZGF0YXNldHMvcGxhbnRlb3MueGxzeCIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCiMjIyMgRXZvbHVjacOzbiBkZWwgbml2ZWwgdGVjbm9sw7NnaWNvIHsudGFic2V0fQ0KDQojIyMjIyBNYWl6IDHCug0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCnBsYW50ZW9zICU+JSBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJNYcOteiAxwrAgVGVtcHJhbm8iLCB2YXJpYWJsZXM9PSJBZG9wY2nDs24gZGUgTlQiKSAlPiUgDQpnZ3Bsb3QoLixtYXBwaW5nID0gYWVzKHggPSBkZXNjcmlwY2lvbl9jYW1wYW5pYSwgeSA9IHZhbG9yZXMsIGdyb3VwPW5pdmVsLGZpbGwgPSBhcy5mYWN0b3IoZGVzY3JpcGNpb25fbml2ZWwpKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCh+ZGVzY3JpcGNpb25fem9uYV9yZXRhYSkrICB0aGVtZV9idygpKw0KICBsYWJzKHRpdGxlID0gICJOaXZlbCB0ZWNub2zDs2dpY28gcG9yIHpvbmEgLSBNYcOteiB0ZW1wcmFubyIpKw0KICBsYWJzKHg9IkNhbXBhw7FhIiwgZmlsbD0iTml2ZWwgdGVjbm9sw7NnaWNvIikrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIg0KICAgICAgICApIA0KYGBgDQoNCiMjIyMjIE1haXogVGFyZGlvIHkgMsK6DQpgYGB7ciwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9OSwgZWNobz1UUlVFfQ0KcGxhbnRlb3MgJT4lIGZpbHRlcihkZXNjcmlwY2lvbl9ncmFubz09Ik1hw616IDHCsCBUYXJkaW8geSAywrAiLCB2YXJpYWJsZXM9PSJBZG9wY2nDs24gZGUgTlQiKSAlPiUgDQpnZ3Bsb3QoLixtYXBwaW5nID0gYWVzKHggPSBkZXNjcmlwY2lvbl9jYW1wYW5pYSwgeSA9IHZhbG9yZXMsIGdyb3VwPW5pdmVsLGZpbGwgPSBhcy5mYWN0b3IoZGVzY3JpcGNpb25fbml2ZWwpKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCh+ZGVzY3JpcGNpb25fem9uYV9yZXRhYSkrICB0aGVtZV9idygpKw0KICBsYWJzKHRpdGxlID0gICJOaXZlbCB0ZWNub2zDs2dpY28gcG9yIHpvbmEgLSBNYcOteiB0YXJkw61vIikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBmaWxsPSJOaXZlbCB0ZWNub2zDs2dpY28iKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICAgICAgICkgDQpgYGANCg0KDQojIyMjIyBTb2phDQpgYGB7ciwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9OSwgZWNobz1UUlVFfQ0KcGxhbnRlb3MgJT4lIGZpbHRlcihkZXNjcmlwY2lvbl9ncmFubz09IlNvamEgMcKwIiwgdmFyaWFibGVzPT0iQWRvcGNpw7NuIGRlIE5UIikgJT4lIA0KZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh4ID0gZGVzY3JpcGNpb25fY2FtcGFuaWEsIHkgPSB2YWxvcmVzLCBncm91cD1uaXZlbCxmaWxsID0gYXMuZmFjdG9yKGRlc2NyaXBjaW9uX25pdmVsKSkpICsNCiAgZ2VvbV9jb2woKSArDQogIGZhY2V0X3dyYXAofmRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpKyAgdGhlbWVfYncoKSsNCiAgbGFicyh0aXRsZSA9ICAiTml2ZWwgdGVjbm9sw7NnaWNvIHBvciB6b25hIC1Tb2phIikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBmaWxsPSJOaXZlbCB0ZWNub2zDs2dpY28iKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICAgICAgICkgDQoNCmBgYA0KDQojIyMjIyBUcmlnbw0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCnBsYW50ZW9zICU+JSBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJUcmlnbyIgLCB2YXJpYWJsZXM9PSJBZG9wY2nDs24gZGUgTlQiKSAlPiUgDQpnZ3Bsb3QoLixtYXBwaW5nID0gYWVzKHggPSBkZXNjcmlwY2lvbl9jYW1wYW5pYSwgeSA9IHZhbG9yZXMsIGdyb3VwPW5pdmVsLGZpbGwgPSBhcy5mYWN0b3IoZGVzY3JpcGNpb25fbml2ZWwpKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCh+ZGVzY3JpcGNpb25fem9uYV9yZXRhYSkrICB0aGVtZV9idygpKw0KICBsYWJzKHRpdGxlID0gICJOaXZlbCB0ZWNub2zDs2dpY28gcG9yIHpvbmEgLVRyaWdvIikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBmaWxsPSJOaXZlbCB0ZWNub2zDs2dpY28iKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICAgICAgICkgDQpgYGANCiMjIyMjIEdpcmFzb2wNCmBgYHtyLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD05LCBlY2hvPVRSVUV9DQpwbGFudGVvcyAlPiUgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iR2lyYXNvbCIgLCB2YXJpYWJsZXM9PSJBZG9wY2nDs24gZGUgTlQiKSAlPiUgDQpnZ3Bsb3QoLixtYXBwaW5nID0gYWVzKHggPSBkZXNjcmlwY2lvbl9jYW1wYW5pYSwgeSA9IHZhbG9yZXMsIGdyb3VwPW5pdmVsLGZpbGwgPSBhcy5mYWN0b3IoZGVzY3JpcGNpb25fbml2ZWwpKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCh+ZGVzY3JpcGNpb25fem9uYV9yZXRhYSkrICB0aGVtZV9idygpKw0KICBsYWJzKHRpdGxlID0gICJOaXZlbCB0ZWNub2zDs2dpY28gcG9yIHpvbmEgLSBHaXJhc29sIikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBmaWxsPSJOaXZlbCB0ZWNub2zDs2dpY28iKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICAgICAgICkgDQpgYGANCiMjIyMjIENlYmFkYQ0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCnBsYW50ZW9zICU+JSBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJDZWJhZGEiICwgdmFyaWFibGVzPT0iQWRvcGNpw7NuIGRlIE5UIikgJT4lIA0KZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh4ID0gZGVzY3JpcGNpb25fY2FtcGFuaWEsIHkgPSB2YWxvcmVzLCBncm91cD1uaXZlbCxmaWxsID0gYXMuZmFjdG9yKGRlc2NyaXBjaW9uX25pdmVsKSkpICsNCiAgZ2VvbV9jb2woKSArDQogIGZhY2V0X3dyYXAofmRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpKyAgdGhlbWVfYncoKSsNCiAgbGFicyh0aXRsZSA9ICAiTml2ZWwgdGVjbm9sw7NnaWNvIHBvciB6b25hIC1DZWJhZGEiKSsNCiAgbGFicyh4PSJDYW1wYcOxYSIsIGZpbGw9Ik5pdmVsIHRlY25vbMOzZ2ljbyIpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCINCiAgICAgICAgKSANCg0KYGBgDQoNCiMjIyMgey19DQoNCiMjIyMgRG9zaXMgZGUgZmVydGlsaXphY2nDs24NCg0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCiNHcmFmaWNvDQpwbGFudGVvcyAlPiUgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iTWHDrXogMcKwIFRlbXByYW5vIiwgdmFyaWFibGVzPT0iVXJlYSIpICAlPiUgICNmaWx0cm8gY3VsdGl2bw0KZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh4ID0gZGVzY3JpcGNpb25fY2FtcGFuaWEsDQogICAgICAgICAgICAgICAgICAgICAgIHkgPSB2YWxvcmVzLCBncm91cD1uaXZlbCxjb2xvciA9IGFzLmZhY3RvcihkZXNjcmlwY2lvbl9uaXZlbCkpKSArDQogIGdlb21fbGluZSgpICsgZ2VvbV9wb2ludCgpKw0KICBmYWNldF93cmFwKH5kZXNjcmlwY2lvbl96b25hX3JldGFhKSArICANCiAgdGhlbWVfYncoKSArDQogIGxhYnModGl0bGUgPSAgIkZlcnRpbGl6YWNpw7NuIGNvbiBVcmVhIChrZy9oYSkgZW4gTWHDrXogdGVtcHJhbm8iKSsNCiAgbGFicyh4PSJDYW1wYcOxYSIsIGNvbG9yPSJOaXZlbCB0ZWNub2zDs2dpY28iKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iDQogICAgICAgICkNCmBgYA0KDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD05LCBlY2hvPVRSVUV9DQojR3JhZmljbw0KcGxhbnRlb3NfcG9uZCAlPiUgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iTWHDrXogMcKwIFRlbXByYW5vIiwgdmFyaWFibGVzPT0iVXJlYSIpICAlPiUgICNmaWx0cm8gY3VsdGl2bw0KZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh4ID0gZGVzY3JpcGNpb25fY2FtcGFuaWEsDQogICAgICAgICAgICAgICAgICAgICAgIHkgPSB2YWxvcmVzLCBncm91cD0xKSkgKw0KICBnZW9tX2xpbmUoKSArIGdlb21fcG9pbnQoKSsNCiAgZmFjZXRfd3JhcCh+ZGVzY3JpcGNpb25fem9uYV9yZXRhYSkgKyAgDQogIHRoZW1lX2J3KCkgKw0KICBsYWJzKHRpdGxlID0gICJGZXJ0aWxpemFjacOzbiBjb24gVXJlYSAoa2cvaGEpIGVuIE1hw616IHRlbXByYW5vIikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBjb2xvcj0iTml2ZWwgdGVjbm9sw7NnaWNvIikrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIg0KICAgICAgICApDQpgYGANCg0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCiNHcmFmaWNvDQpwbGFudGVvc19wb25kICU+JSBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJUcmlnbyIsIHZhcmlhYmxlcz09IlVyZWEiKSAgJT4lICAjZmlsdHJvIGN1bHRpdm8NCmdncGxvdCguLG1hcHBpbmcgPSBhZXMoeCA9IGRlc2NyaXBjaW9uX2NhbXBhbmlhLA0KICAgICAgICAgICAgICAgICAgICAgICB5ID0gdmFsb3JlcywgZ3JvdXA9MSkpICsNCiAgZ2VvbV9saW5lKCkgKyBnZW9tX3BvaW50KCkrDQogIGZhY2V0X3dyYXAofmRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpICsgIA0KICB0aGVtZV9idygpICsNCiAgbGFicyh0aXRsZSA9ICAiRmVydGlsaXphY2nDs24gY29uIFVyZWEgKGtnL2hhKSBlbiBUcmlnbyIpKw0KICBsYWJzKHg9IkNhbXBhw7FhIiwgY29sb3I9Ik5pdmVsIHRlY25vbMOzZ2ljbyIpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSINCiAgICAgICAgKQ0KYGBgDQoNCiMjIyBQcmVjaW9zDQoNCmh0dHBzOi8vZW1vcmllYmVjay5naXRodWIuaW8vUi10dXRvcmlhbHMvcHVycnIvIw0KDQpgYGB7cn0NCnVuaXF1ZShwbGFudGVvcyR2YXJpYWJsZXMpICU+JSB3cml0ZS54bHN4KCJkYXRhc2V0cy9pbnN1bW9zX3BsYW50ZW9zLnhsc3giKQ0KYGBgDQoNCg0KDQo=